VMware Aria Automation for Secure Clouds

Comparing Resource Structures and Organization Tools for the Big Three Cloud Providers

Welcome to the third part of the blog series on comparing (Identity and Access Management) IAM and Security Models for the “Big Three” public cloud providers.  This journey started with a blog post focused on what types of principals exist in each provider and was accompanied by a quick overview of the organization of these principals and the authentication mechanics, or for short – the “Who” part of the IAM equation. The second post in the series covered – what permissions exist in each provider, or “How” these permissions are structured and how they get assigned to principals. In the 3rd blog of this series, we’ll look at the “What” – resources, their structure and organization, for the big three cloud providers – AWS, Azure and Google Cloud. 

AWS  

Resources  

AWS Resources are the objects that get created when the respective AWS APIs are called – continuing our long running example with EC2 – when performing an API call to the RunInstances (or `aws ec2 run-instances` if you prefer the AWS CLI) operation, a resource of type EC2 instance is created with the specified parameters, such as AMI, region, availability zone (AZ) or subnet ID. When calling AWS APIs, the resource type is generally the noun in the operation name, e.g. – “instances” in our previous example. 

VMware Aria Automation for Secure Clouds (formerly CloudHealth Secure State) assigns each supported cloud resource an Entity Type, which is composed of the cloud provider, service, and resource name, so in this example, if you want to find EC2 instances, you can perform the following SSQL query which leverages VMware Aria Automation for Secure Clouds’ interconnected cloud security model: 

EntityType = AWS.EC2.Instance 

Alternatively, you can also use VMware Aria Automation for Secure Clouds’ Inventory view provided within Explore capability, which gives  a bird’s eye view of multiple cloud resources, grouped by their function in the larger Cloud ecosystem such as, Compute, Security and Identity, Storage, Networking and Content Delivery and so on. 

Generally, when viewing the AWS Console, there are fewer options to list resources from different regions within the same screen. This is different from Azure and GCP and could be inconvenient, but VMware Aria Automation for Secure Clouds Explore inventory can give you a centralized view of all resources for your entire organization or a specific project.   

During September’ 2021, Amazon launched EC2 Global View – a new interface that shows EC2 resources from all regions. Unfortunately, this support is not extended to all services, unlike VMware Aria Automation for Secure Clouds. One possible reason for this is the relative independence of regions within AWS – each region has its own domain for API calls, and this flexibility means outages in AWS regions generally do not affect other regions, and allows easy support for AWS Outposts, a self-hosted version of the AWS stack, which is implemented essentially as a private region. 

Each AWS resource has an Amazon Resource Number, or ARN. If you’ve used the AWS Console to create a resource, you’ve probably already seen examples of ARN, but here’s a few of them: 

  • Example #1
arn:aws:ec2:us-west-1:123456789012:instance/i-12345678 
  • Example #2
arn:aws:iam::123456789012:policy/managed-policy-example
  • Example #3  
arn:aws:s3:::access-logs-bucket123

Normally, the AWS Console provides a way to see the ARN of a particular resource, but this isn’t always the case, notably there is no convenient way to get the ARN of an EC2 instance outside of “filling it in” on your own. 

While there are obvious patterns present in these ARNs, the format of ARNs is not so trivial, and therefore warrants some discussion. ARNs consist of several components, separated by colons (“:”). These components are (in order): 

  1. The literal string “arn” – always present, does not imply any information 
  1. The Partition – one of “:” 
  1. “aws” – Commercial, or more colloquially “Normal” AWS. This is the most popular partition and the one talked about by default. 
  1. “aws-cn” – Chinese AWS, created to align with Chinese data sovereignty laws 
  1. “aws-us-gov” – US Government cloud, created to allow US Government organizations to utilize the benefits of AWS 
  1. The Service – the short identifier of an AWS service, such as `ec2` for EC2, `s3` for S3 and `eks` for the Elastic Kubernetes Service 
  1. The Region – the region in which the resource resides, such as `us-east-1`, `eu-west-1`, etc. 
  1. The Account ID – the AWS Account Number or Account ID 
  1. The Resource Path – Not all resource types support Resource Paths, but IAM resources generally do. The role of resource paths is to allow finer-grained resource (including principal) selection within AWS Policies 
  1. The Resource ID – an identifier for the resource itself, often this is the “Name” of the resource, such as in S3 buckets, DynamoDB tables, Lambda functions, IAM Policies, Roles, Users, and many others. A notable exception to this convention is how EC2 instances are identified – their names are mere tags and instead random-generated Instance IDs are assigned at creation 

There are multiple asterisks attached to this breakdown – as demonstrated in the examples above, the Region could be missing (example #2), since IAM resources such as policies are global; the Account ID could be missing (example #3), since S3 bucket names are globally unique and do not fall within the hierarchy of accounts. Additionally, Resource Paths are not available for many (if not most) services; sometimes the separator between Resource Type and Resource ID is a forward slash (“/”) instead of a colon, and many others. 

The official specification of ARNs can be found in the AWS General Reference, but it should be noted that this specification is more a definition of what IAM ARN are, as opposed to what ARNs are. To demonstrate the difference – the above reference states that ARNs can include wildcards, such as in

 arn:aws:iam::123456789012:user/Development/product_1234/* 

but you couldn’t create an IAM user with the name ‘*’ – this is a wildcard, as used in IAM ARNs, that are provided (for example) in the Resources field of IAM Policies. More information can be found in IAM identifiers documentation, and the final authority on what can be provided as part of a Resource field is in the IAM JSON policy elements: Resource documentation

Conditions 

The “Using policy variables in resource ARNs” section provides a good segue into the adjacent topic of Conditions: when writing a policy, its author has the option to provide conditions that determine if the particular policy statement applies. 

Conditions can make use of a combination of condition keys, operators, literal values and policy variables to determine the applicability of the statement to resources or principals. These combinations are expressed in JSON as an expression tree and can include a variety of comparison operators (see here for the full operator list) for different types, such as `StringEqualsIgnoreCase` for case-insensitive string comparison, or `IpAddress` for checking if an IP address matches or is within the specified argument. The condition keys themselves depend on the specific Action – there are global condition keys, that are present when any AWS API request is evaluated, while other condition keys are only available for some services, or even specific to an API Action (see the “Global condition keys”, “IAM condition keys” and “Actions, resources and condition keys” chapters of the AWS IAM Policy Reference). Finally, there are Variables – values that can be used as operands, such as `aws:CurrentTime`, which is always available for time-based conditions. 

Resource Groups & Tag Editor 

To enable users to better group resources and manage them in bulk, AWS provides a rudimentary primitive of Resource Group. A Resource Group is a resource itself, and there are API actions that can be performed over a Resource Group, but these generally refer to the Resource Group as an organizational primitive, rather than as a proxy for the resources that are part of the group. 

There are 2 types of Resource Groups:  

  1. Tag based resource groups have their resources identified by the presence or value of a tag 
  1. CloudFormation stack-based resource groups contain resources that are created as part of a particular CloudFormation stack. 

Authors of IAM policies can make use of Resource Groups-related condition keys, such as `aws:ResourceTag`, `aws:RequestTag`, and `aws:TagKeys`. In AWS, Resource Groups are mere sets of resources, without an implicit hierarchy, or the simple guarantee that a resource is contained within a single Resource Group – when compared to the central role of Resource Groups in Azure, in AWS they were provided later. 

Resource-based policies 

Unlike the other 2 cloud providers, AWS offers an additional type of policy: 

Resource-based policies always apply to a single resource and therefore cannot be reused. They are the alternative to Identity-based policies and are evaluated before any applicable Identity-based policies. Generally, an explicit Allow statement from a Resource-based policy is not a prerequisite for access to the resource, but there are exceptions to this logic. As examples, when you try to assume an IAM role, you need an explicit Allow in the Role’s Trust relationship section in the AWS Console. This is the reason why VMware Aria Automation for Secure Clouds distinguishes between AWS.IAM.ResourcePolicy (a type for resource policies) and AWS.IAM.TrustPolicy (a type specifically for an IAM Role’s resource policy, commonly referred to as Trust policy). Another example is KMS keys ,which also require any principal attempting access to be covered by an explicit Allow statement in the KMS Resource policy. 

Resource-based policies are much less consistent than Identity-based policies – their availability and impact on the Policy Evaluation process varies across services and resource types. 

Azure  

Resources 

In general, resources in Azure are organized in a much stricter fashion. Just like in AWS, resources in Azure are created using the Azure APIs, and similar to AWS, the type of resource created is mentioned in the API Action. Using  Virtual Machines as an example again, the Action to create an Azure VM is Microsoft.Compute/virtualMachines/write and this API call  will create a Virtual Machine within the Microsoft.Compute service. 

Each resource in Azure has a Resource ID, which specifies the resource uniquely within the Azure cloud. Here’s a few examples of such resources: 

  • Example #1 
/subscriptions/12345678-90ab-cdef-1234-567890abcdef/resourceGroups/VMTest_group/providers/Microsoft.Compute/virtualMachines/VMTest 
  • Example #2 
/subscriptions/12345678-90ab-cdef-1234-567890abcdef/resourcegroups/infra-team-resources/providers/Microsoft.ManagedIdentity/userAssignedIdentities/aks-host-identity 
  • Example #3 
/subscriptions/12345678-90ab-cdef-1234-567890abcdef/resourcegroups/aks-dev-cluster/providers/Microsoft.ContainerService/managedClusters/aks-dev-cluster-1 

The pattern here is much simpler and more reliable in its structure than ARNs. An Azure Resource ID is a path-like string. It is composed of the following components, separated by forward slashes (“/”): 

  1. The literal string “subscriptions” 
  1. The Subscription ID – a UUID (randomly chosen when creating the subscription) that uniquely defines the Azure subscription 
  1. The literal string “resourceGroups” 
  1. The Resource Group Name – a user-provided name that is unique within resource groups of that subscription 

(Note: Resource IDs for Resource Groups don’t contain the remaining components) 

  1. The literal string “providers” 
  1. The Provider of an Azure Service, such as Microsoft.Compute. You can find the full list of resource providers for Azure services in the official documentation. 
  1. The Resource Type – such as `virtualMachines`, `userAssignedIdentities`, or `managedClusters`. This component, along with the Provider, fully identifies the resource type. 
  1. The Resource Name – a user-provided name that is unique within the particular resource group 

The components listed above are generally present for each resource and exceptions to the rules are, well, exceptional. You can see the Azure Resource ID for each resource by clicking “Properties” in the “Settings” section of the left side bar: 

Azure Console

Conditions 

Azure also supports conditionally granting permissions to principals, but does so through Role Assignments, rather than Roles (remember that Azure Roles are essentially permission grants, are very similar in function to AWS Policies and are nothing like AWS Roles). It is worth noting that most Azure Roles do not support conditions in their assignments: in fact only roles that contain storage blob data actions can currently make use of conditions (recall that Azure distinguishes between control plane and data plane actions). 

Azure Conditions are written in a domain-specific language (DSL), and as such are stored as strings within the native JSON format for Role Assignments. 

Here’s how a Role Assignment looks like when viewed through the `az` Azure CLI: 

~ az role assignment list --assignee yavor@contoso.onmicrosoft.com 
  { 
    "canDelegate": null, 
    "condition": "(\n (\n  !(ActionMatches{'Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read'} AND NOT SubOperationMatches{'Blob.List'})\n )\n OR \n (\n  @Resource[Microsoft.Storage/storageAccounts/blobServices/containers/blobs:path] StringStartsWith 'test'\n )\n)\nAND\n(\n (\n  !(ActionMatches{'Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read'} AND NOT SubOperationMatches{'Blob.List'})\n )\n OR \n (\n  @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:name] StringEquals 'Test2'\n )\n)", 
    "conditionVersion": "2.0", 
    "description": null, 
    "id": "/subscriptions/12345678-90ab-cdef-1234-567890abcdef/providers/Microsoft.Authorization/roleAssignments/87654321-90ab-cdef-1234-567890abcdef", 

    “name”: “87654321-90ab-cdef-1234-567890abcdef”, 

    "principalId": "43218765-90ab-cdef-1234-567890abcdef", 
    "principalName": "yavor@contoso.onmicrosoft.com", 
    "principalType": "User", 
    "roleDefinitionId": "/subscriptions/12345678-90ab-cdef-1234-567890abcdef/providers/Microsoft.Authorization/roleDefinitions/56781234-90ab-cdef-1234-567890abcdef", 
    "roleDefinitionName": "Storage Blob Data Owner", 
    "scope": "/subscriptions/12345678-90ab-cdef-1234-567890abcdef", 
    "type": "Microsoft.Authorization/roleAssignments" 
  } 

As you can see, the condition field consists of multiple conditions and statements, joined by AND/OR. The statements themselves apply to one or more Action (listed in the Role Definition) and can make use of various attributes and operators. The operators are like those provided in AWS, while the attributes fall within 3 categories: 

  1. Resource – attributes, related to the resource that the Action applies to 
  1. Request – attributes, related to the Action request, such as the storage blob path 
  1. Principal – attributes, related to the Principal making the Action request. Note that in order to use such attributes, you need an Azure AD Premium P1 or P2 license, which further limits the usage of Conditions. 

You can see the full documentation for Condition syntax and operators in the Azure docs

There is no direct equivalent to AWS Variables which you can use to for example, provide access to each user only to the Resource Group with the same name – for that you need to create individual Role Assignments.

Unlike AWS, where Conditions are fundamental to implementing access control, in Azure conditions are in Preview and have limited applications. Due to that, attribute-based access control (ABAC) support in Azure is very limited. 

Resource Groups 

Here is where Azure’s resource hierarchy truly shines – in Azure, Resource Groups are first class primitives and are fundamental to organizing resources. Each resource belongs to exactly one Resource Group, and the choice of Resource Group is left entirely to the user – in this way Microsoft provides a convenient way to logically group related resources – whether by function, by department, or something entirely different. 

Just a reminder that all Role Assignments specify a scope at which they are applied. The recommended scope is a Resource Group, or a more narrowly defined scope (i.e. a resource type within a resource group, or a concrete resource). This generally results in role assignments that are tightly scoped and do not grant a large set of privileges over a large set of resources – there is just no point, as the resources a user might be interested in are probably already organized in a Resource Group. 

The expressive power and utility, provided by Resource Groups is significant, but that also means the quality of the access control (i.e. the correctness, conciseness, maintainability and strictness of the permission grants) depends on the quality of the logical organization of resources into groups. It is very hard to remedy access control issues, caused by badly organized resources through the use of Role Assignments – the resource group-based access control model is ingrained deeply into the Azure architecture. 

Resource-based permission management 

Azure does not provide resource-based policies as in the case of AWS or Google Cloud.

Google Cloud 

Resources 

Resources in GCP also have a unique identifier – “Full Resource Name” – that can be used to refer to them in any context, but in the GCP world this identifier is rarely utilized by users. As an example, there is no easy way to see the full resource name of a Compute Engine VM instance from the GCP console. Additionally, a URI (which is very similar to the Full Resource Name) exists for each resource and can be obtained through the `gcloud` CLI by passing the `–uri` flag: 

The URI is structured similarly to the Azure resource IDs, being composed of the following elements: 

  1. The literal string “https://www.googleapis.com/” 
  1. The short Service ID – in this case “compute” for “Compute Engine” 
  1. The Version of the service – in this case “v1” 
  1. The literal string “projects” 
  1. The Project ID – a small caps string generated from the user-provided Project Name 
  1. The literal string “zones” 
  1. The Availability Zone of the resource 
  1. The Resource Type – in this case “instance” 
  1. The Name of the resource – such as “instance-1”, “instance-2”, “instance-2-cc” from the above screenshot 

Conditions 

Conditions in GCP are provided when assigning a role to members (i.e. EntityType `GCP.IAM.RoleBinding` in VMware Aria Automation for Secure Clouds). They are stored in a subset of the Common Expression Language (CEL), a Google-backed rudimentary language that is part of the protobuf ecosystem. In order to navigate this language, the GCP console provides 2 interfaces for writing conditions –  

  1. Condition Builder, a simple visual editor; and  
  1. Condition Editor – a text editor for directly writing conditions by hand. 

In terms of primitives, the language supports variables, operators (that depend on the type of the operands), logical operators (not, and, or), functions (such as `startsWith` – the distinction between functions and operators is merely syntactic) and values (user-provided constants). The operators include what you would normally expect, such as ==, <, >, etc. The available variables and functions are split in 2 categories – “Time” and “Resource”. A notable omission is the complete lack of Principal-related variables at the top level – even Azure provides this feature, albeit at a cost. 

Resource Organization 

In the Google Cloud Platform, resource organization is closer to Azure than to AWS in terms of its overall design. There is a strong Resource Hierarchy in GCP – all resources belong to a particular project, all projects have a parent with that parent being either a folder (an abstract group of projects and/or other folders), and at the root of it all sits an organization. The projects, folders and the organization are essentially the only available “logical attach points” (or scopes) for assigning IAM Roles to principals. 

Of course, Resource-based conditions provide the ability to check for the presence of Tags, thus enabling the implementation of attribute-based access control (ABAC) patterns. 

Resource-based permission management 

GCP does not provide any form of permission management tool directly attachable to a resource. 

Closing Remarks

As a conclusion, let’s try and summarize the available resource management and organization tools for the big three cloud providers. 

AWS takes the pragmatic approach – providing  powerful and expressive tools to users. However, when looking at the big picture, the lack of a unifying access control vision seems hard to miss: For anything there are multiple approaches and tools – inline policies, managed policies, resource-based policies. The result of it all is that the interactions between the different types of IAM tools become hard to track and reason about.  

Azure goes in the other direction: there’s a clear resource hierarchy, the rules are generally simple and don’t carry multiple asterisks attached to each one. Things get murkier with conditions, where Azure hides some of the goodies (Principal-based conditions) behind the higher tier AzureAD subscriptions, limiting user access. Overall, it is very easy to reason about Azure access control, especially compared to the behemoth of a model that AWS is sporting. And as always, this comes at the price of some expressiveness – AWS conditions are unrivaled in this regard. 

GCP is also near the Azure camp in that there aren’t many IAM tools, but instead there is a strong focus on the need to organize resources properly. The omission of general Principal-based conditions might raise some eyebrows, but tags and tag-based conditions can generally get the job done for the most common access control models, employed by organizations. 

In three comprehensive blog articles on IAM and security models in public clouds, we have covered discussions on principals, permissions and their management and resource management tools. As VMware Aria Automation for Secure Clouds enables organizations to use public cloud services and Kubernetes securely, continuing to deliver on this commitment, we have recently added the capability of entitlements visibility for AWS so that you can identify and better manage excessive permissions that can give rise to risks across cloud infrastructure. 

If you’re looking for even more information, fill this form to get in touch with us directly. Our team would be happy to answer questions and walk you through the capabilities of the VMware Aria Automation for Secure Clouds platform. If you prefer to get a firsthand experience of our cloud configuration security platform fill out a simple form to get instant access to your free VMware Aria Automation for Secure Clouds account. 

 

Comments

Leave a Reply

Your email address will not be published.