AWS allows tags, arbitrary key-value pairs, to be assigned to many resources. Tags can be used to categorize resources however you like. Some examples:
Once you have tagged your resources, you can search and filter based on tags. That’s not very interesting from a security perspective. Far more interesting is using tags to implement attribute-based access control (ABAC).
The “normal” AWS authorization scheme is known as Role-Based Access Control (RBAC): you define “roles” corresponding to service or job functions (implemented as IAM Users or Roles) and assign them the privileges necessary for those functions. A disadvantage of this scheme is that when you add new resources to your environment, the privileges assigned to your principals may need to be modified. This doesn’t scale particularly well with large numbers of resources. Using resource-based permission policies rather than identity-based permission policies can help with this, but that doesn’t scale well with large numbers of principals (especially since AWS doesn’t allow permissions to be granted to groups using resource-based permission policies). Also, not all resources support resource-based permission policies.
An alternative authorization scheme is to assign tags to principals and resources then grant permissions based on the combinations of principal and resource tags. For instance, all principals tagged as belonging to project QuarkEagle can be allowed to access resources also tagged as belonging to project QuarkEagle, while principals tagged with project CrunchyNugget can only access resources also tagged CrunchyNugget. This approach isn’t suitable for all scenarios but can result in significantly fewer and smaller permission policies that rarely need to be updated even as new principals and resources are added to accounts. This scheme is known as “attribute-based access control” (ABAC) or “tag-based access control” (TBAC), depending on the source.
In practice, you’re not likely to want a “pure” ABAC environment: most ABAC deployments will combine it with elements of RBAC.
Apart from tags themselves, there are no new fundamental concepts in AWS for ABAC. You still have principals and resources with identity-based and resource-based permission policies. However, instead of having a lot of specifics in the resource and principal fields, an ABAC permission policy will have wildcards in those fields with the real logic implemented using conditions. There are four main condition keys that relate to tagging:
Some examples are in order to clarify how these condition keys are be used.
If a principal is only permitted to publish messages to SNS Topics belonging to project QuarkEagle, then it might have this permission policy statement:
{ "Effect": "Allow", "Action": "sns:Publish", "Resource": "arn:aws:sns:*:*:*", "Condition": { "StringEquals": { "aws:ResourceTag/project": "QuarkEagle" } } }
This allows your principal to publish to any SNS Topic, so long as that Topic has a tag named “project” whose value is “QuarkEagle”. If tiy want to go a step farther, you could tag your principals with their associated projects and then use this permission policy statement instead:
{ "Effect": "Allow", "Action": "sns:Publish", "Resource": "arn:aws:sns:*:*:*", "Condition": { "StringEquals": { "aws:ResourceTag/project": "${aws:PrincipalTag/project}" } } }
Now any principal that has a tag named “project” with the value “QuarkEagle” can publish to any SNS topic whose “project” tag is also “QuarkEagle” and any principal whose “project” tag is “CrunchyNugget” can publish to any topic that is also tagged “CrunchyNugget” — no need for permission policies that know about every tag value in use.
If your principals can create and delete SNS Topics, then you should make sure that they can only create properly tagged ones and can only delete ones with the proper tags. Similarly, if you allow your principals to set or unset tags, then you probably don’t want to allow them to change the “project” tag values on their resources. To enforce that, you might give them permission policy statements like this:
{ "Effect": "Allow", "Action": [ "sns:CreateTopic", "sns:TagResource" ], "Resource": "arn:aws:sns:*:*:*", "Condition": { "StringEquals": { "aws:RequestTag/project": "${aws:PrincipalTag/project}", "aws:ResourceTag/project": "${aws:PrincipalTag/project}" } } }, { "Effect": "Allow", "Action": "sns:DeleteTopic", "Resource": "arn:aws:sns:*:*:*", "Condition": { "StringEquals": { "aws:ResourceTag/project": "${aws:PrincipalTag/project}" } } }, { "Effect": "Allow", "Action": [ "sns:TagResource", "sns:UntagResource" ], "Resource": "arn:aws:sns:*:*:*", "Condition": { "StringEquals": { "aws:ResourceTag/project": "${aws:PrincipalTag/project}" }, "ForAllValues:StringNotEquals": { "aws:TagKeys": "project" } } }
ABAC permissions policies are easy to get wrong. Even Amazon has difficulty with them: AWS’ public documentation contains a number of example permission policies similar to the first statement above that do not contain the “StringEquals”: { “aws:ResourceTag/project”: “${aws:PrincipalTag/project}” } condition. Make sure that any ABAC permission policies that you write or review cover all scenarios.
It’s also important that your principals can’t change the “project” tags on themselves. If you need to allow your principals to call iam:TagUser and iam:UntagUser (or their equivalents for Roles), then you should use similar permission policies to prevent them from removing or changing the values of their “project” tags.
If you want to enforce some order on what tags are applied, then you can use a permission policy statement such as the following to prevent principals from setting any tags other than “department”, “project”, and “stage” on SNS Topics:
{ "Effect": "Deny", "Action": "sns:TagResource", "Resource":"arn:aws:sns:*:*:*", "Condition": { "ForAnyValue:StringNotEquals": { "aws:TagKeys": [ "stage", "project", "department" ] } } }
A similar permission policy statement employing aws:RequestTag/… can be used to control the values that may be assigned to tags.
Some services offer a condition key that can be used to make a permission policy statement apply only during resource creation (such as EC2’s ec2:CreateAction); using such a condition in your Policies can make them simpler and easier to understand. For instance, the following permission statement allows a principal to create tagged EC2 resources without allowing any weird ec2:CreateTags abuses:
{ "Effect": "Allow", "Action": [ "ec2:CreateSecurityGroup", "ec2:CreateImage", "ec2:CreateVolume" "ec2:RunInstances" ], "Resource":"*", "Condition": { "StringEquals": { "aws:RequestTag/project": "${aws:PrincipalTag/project}" } } }, { "Effect": "Allow", "Action": "ec2:CreateTags", "Resource": "arn:aws:ec2:*:*:*", "Condition": { "StringEquals": { "ec2:CreateAction": [ "CreateSecurityGroup", "CreateImage", "CreateVolume" "RunInstances" ] } } }
The first statement permits the caller to create a few different EC2 resources so long as they have the same “project” tag value as the caller. Actually setting that tag, even during resource creation, requires a permission for ec2:CreateTags, so the second statement allows the caller to create tags only from those resource-creation API actions. However, this approach has its own flaws: EC2 considers ec2:CreateTags to be a resource-creation action, so make sure that any wildcards that you use in the ec2:CreateAction condition check don’t match ec2:CreateTags.
With proper use of tagging, combined with separate VPCs, it may be possible to put separate applications and separate stages of each application in the same account without allowing, for instance, beta principals to access prod data. Not that I’d recommend this approach: getting the tagging right is a lot of work (and there are many gotchas; see below). If you’re building a new application, it’s usually safer (and easier) to just use separate accounts for each application and stage with cross-account access via Role assumption and VPC peering as needed. But it’s worth considering for big complicated accounts with access control problems: it may be less work to implement ABAC on top of existing applications than it is to disentangle a giant messy account.
AWS services that support tagging have API actions to add and remove tags from resources and to list the tags on a resource. Tagging support was added to many AWS services well after they were first released and ABAC support was grafted on later still. As a result, the implementation of tagging isn’t consistent between services.
The most common patterns for API action names are:
Most resource-creation API actions allow tags to be assigned during resource creation. Assigning a tag this way requires the permission for the tag-setting API action in addition to the resource-creation API action. For instance, to create an SNS Topic, I need permission for the action “sns:CreateTopic“. If I set a tag on a Topic while creating it, then I also need permission for the action “sns:TagResource” even if I never directly call that API action. However, there may still be some resources that support tagging but cannot be tagged at creation or cannot be tagged when created using CloudFormation.
The syntax for setting tags using AWS CLI also differs between services. Most services’ resource-creation and tagging API actions use a “–tags” command-line argument followed by a list of tags to set, but how that list is formatted depends on the service. Some services (including SQS and Lambda) expect “–tags project=QuarkEagle,stage=beta” while others (such as SNS and SSM) expect an argument of the form “–tags Key=project,Value=QuarkEagle Key=stage,Value=beta“. EC2 is an exception; during resource creation, it uses a more elaborate form of the latter syntax: “–tag-specifications ‘ResourceType=security-group,Tags=[{Key=project,Value=QuarkEagle},{Key=stage,Value=beta}]’“.
If you were thinking that it would be really nice for AWS to provide a unified tagging API, you’re not alone. AWS Resource Groups has a tagging API that can operate on most AWS services that support tagging. Besides providing a generic interface to tagging and untagging, this service also provides ways to retrieve all tag keys and values currently in use by an account and to query resources by tag across multiple services. From AWS Console, you can use “aws resourcegrouptaggingapi tag-resources …” to apply tags to arbitrary resources. To do this, you need both a “tag:TagResources” permission and a tagging permission for the resource that you are trying to tag. Untagging is similar. The following is a minimal permission policy to allow a principal to apply tags to a specific SNS Topic (resource constraints aren’t supported on the tag:TagResources permission because the resources are not in the Resource Groups service):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sns:TagResource", "Resource": "arn:aws:sns:us-east-1:111111111111:some-topic" }, { "Effect": "Allow", "Action": "tag:TagResource", "Resource": "*" } ] }
S3 is the special snowflake; there’s a reason why I didn’t use it for my examples above. While most AWS services have API actions that add or remove individual tags, the S3 tagging API operates on the entire set of tags on the object at once: s3:PutObjectTagging and s3:PutBucketTagging replace the full set of tags on the target resource with the given set, while s3:RemoveObjectTagging and s3:RemoveBucketTagging remove all tags from the target resource. If an object has the tags “application”, “stage”, and “owner” and you want to change the value of “owner”, then your call to s3:PutObjectTagging needs to set the “owner” tag to its new value and the “application” and “stage” tags to their current values in order to not lose the other tags. Tags can be retrieved using s3:GetObjectTagging and s3:GetBucketTagging. Unfortunately, the Resource Groups Tagging API does not support objects in S3 so it does not provide a work-around for S3’s weird tagging implementation.
To make the S3 case even more complicated, both Buckets and objects can be tagged but S3 only supports ABAC on objects. Even that support is incomplete: ABAC is not supported for s3:PutObject, s3:DeleteObject, or s3:DeleteObjectVersion calls. S3 also doesn’t support the normal aws:ResourceTag, aws:RequestTag, and aws:TagKeys condition keys at all: you must use S3-specific condition keys:
There may be other services with unusual tagging implementations; I haven’t checked all of them. EC2 has its own tagging condition key “ec2:ResourceTag” but that seems to be a synonym for aws:ResourceTag.
Unfortunately, ABAC support across AWS is incomplete (though improving) and has many implementation inconsistencies across services. Quirks of AWS’ ABAC implementation include:
Service | ABAC support? |
---|---|
EC2 | Yes |
S3 | Partial support for objects using non-standard condition keys; no support for Buckets |
Lambda | For Functions but not for other resource types |
DynamoDB | No |
RDS | Yes |
IAM | Users and Roles only, with exceptions |
Certificate Manager | Yes |
Secrets Manager | Yes |
KMS | Yes |
CloudTrail | Yes |
CloudWatch | Mostly |
CloudFormation | Yes |
API Gateway | Yes (though not for API authorization) |
CloudFront | Yes |
Route 53 | No |
SNS | Yes |
SQS | Yes (added in fall 2022) |
Details on some of those limitations:
Hopefully AWS’ ABAC support will continue to improve over time.
This post is about a rather technical coding strategy choice that arises when implementing cryptographic algorithms on some elliptic curves, namely how to represent elements of the base field. We will be discussing Curve25519 implementations, in particular as part of Ed25519 signatures, as specified in RFC 8032. The most widely…
Authored by Joshua Kamp (main author) and Alberto Segura. Summary Hook and ERMAC are Android based malware families that are both advertised by the actor named “DukeEugene”. Hook is the latest variant to be released by this actor and was first announced at the start of 2023. In this announcement,…
Mathew Vermeer is a doctoral candidate at the Organisation Governance department of the faculty of Technology, Policy and Management of Delft University of Technology. At the same university, he has received both a BSc degree in Computer Science and Engineering, as well as a MSc degree in Computer Science with…