Caution! Wildcards ahead.
All AWS IAM identities (users, groups, roles) and many other AWS resources (e.g. S3 buckets, SNS Topics, etc) rely on IAM policies to define their permissions. It is often necessary (or desirable) to create policies that match to multiple resources, especially when the resource names include a hash or random component that is not known at design time.
Wildcards can be used to enable those use cases and therefore are incredibly powerful (and dangerous).
Wildcard Reference
Available wildcards are:
?
matches any single character in a string (or ARN).*
can be used by itself to indicateall values
.*
can also be used within a string (or ARN) to match zero or more characters.
IAM Policies are JSON documents that are composed of an optional header and one or more statements
.
Each <statement_block>
is further composed of required and optional elements
, a few of which do not support use of wildcards:
Element | Usage | All Resource Support | Multi‑Char Wildcard Support | Single‑Char Wildcard Support |
---|---|---|---|---|
Sid | "Sid": "{sid_string}" | No | No | No |
Effect | "Effect": ("Allow" or "Deny") | No | No | No |
Principal | ("Principal" or "NotPrincipal") : ("*" or <principal_map>) | Yes | No | No |
Action | ("Action" or "NotAction") : ("*" or [<action_string>, ...]) | Yes | Yes | Yes |
Resource | ("Resource" or "NotResource") : ("*" or [<resource_string>, ...] | Yes | Yes | Yes |
Condition | "Condition" : { <condition_map> } | No | Yes | Yes |
Principal Element
("Principal" | "NotPrincipal") : ("*" | <principal_map>)
*
can be used inside a <principal_block>
to specify everyone (or anonymous) but it cannot be used as a string wildcard to match on multiple principals:
Valid examples:
"Principal": "*""Principal": { "AWS": "*" }"Principal": { "AWS": ["arn:aws:iam::111222333444:user/dschrute","arn:aws:iam::444455556666:root"]}"Principal": { "AWS": ["*","arn:aws:iam::444455556666:root"]}
Invalid
examples:
"Principal": { "AWS": "arn:aws:iam::444455556666:*" }"Principal": { "AWS": "arn:aws:sts::777888998900:assumed-role/superuser/*" }
Action Element
("Action" | "NotAction") : ("*" | [<action_string>, <action_string>, ...])
- A single
*
can be used by itself in the<action_block>
to specify all actions. - Multiple
*
's can be used as string wildcards in the<action_string>
, but not in thenamespace
. - Multiple
?
's can be used to match any single char in theaction name
part of the<action_string>
.
{ This is undocumented and seems of little value, but it works. }
Valid examples:
"Action": "*""Action": "s3:*""Action":["s3:Get*","s3:List*"]"Action": "iam:*AccessKey*""Action": "iam:*AccessKey?"
Invalid
examples:
"Action": "s*:*""Action": "s??:*"
Resource Element
("Resource" | "NotResource") : ("*" | [<resource_string>, <resource_string>, ...]
- A single
*
can be used by itself in the<resource_block>
to specify all resources. - Multiple
*
's can be used as string wildcards in the<resource_string>
. - Multiple
?
's can be used to match single chars in the<resource_string>
.
Valid examples:
"Resource": "*""Resource": "arn:aws:sns:us-east-2:*:aaa_api_handler" // All Accounts"Resource": "arn:*:sns:*:*:aaa_api_handler" // partition, region and account wildcards"Resource": "arn:aws:sns:*:111222333444:aaa?api?handler" // Any region and not sure if using `-` or `_`
Invalid
examples:
"Resource": "arn:aws:*:aws_api_handler" // Spanning sections of the ARN is not allowed
Condition Element
The optional <condition_block>
specifies the conditions under which the policy is in effect. The <condition_block>
is comprised of three parts:
"Condition" : { "{condition-operator}" : { "{condition-key}" : "{condition-value}" }}
Wildcards are allowed as part of the {condition-value}
for a subset of string
and arn
condition operators:
Condition Operator | Allows Wildcards |
---|---|
ArnEquals | Yes |
ArnLike | Yes |
ArnNotEquals | Yes |
ArnNotLike | Yes |
ArnEqualsIfExists | Yes |
ArnLikeIfExists | Yes |
ArnNotEqualsIfExists | Yes |
ArnNotLikeIfExists | Yes |
Bool | No |
BinaryEquals | No |
IpAddress | No |
NotIpAddress | No |
Null | No |
Numeric* | No |
StringEquals | No |
StringNotEquals | No |
StringEqualsIgnoreCase | No |
StringNotEqualsIgnoreCase | No |
StringLike | Yes |
StringNotLike | Yes |
StringLikeIfExists | Yes |
StringNotLikeIfExists | Yes |
Valid examples:
"Condition": {"StringNotLike": {"aws:PrincipalTag/cost-center": "*scranton*"}}"Condition": {"ArnLike": {"aws:SourceArn": "arn:aws:sns:*"}}"Condition": {"StringLikeIfExists": {"ec2:InstanceType": ["t1.*","t2.*","m3.*"]}}
Note: ARNs and Strings behave differently:
ARNs and String conditionals work slightly differently when it comes to wildcards:
For
string
types wildcards are only supported in theStringLike*
andStringNotLike*
condition operations, theStringEquals
andStringNotEquals
varients do not support them:Invalid:
"Condition" : { "StringEquals" : { "aws:username" : "*schrute*" }}
However
ArnEquals
andArnLike
are functionally equivalent and both support wildcards.Valid:
"Condition": {"ArnEquals": {"aws:SourceArn": "arn:aws:sns:*"}}
Bonus: How to escape special characters:
Since wildcards match multiple values, how would you go about explictly matching against a string that includes *
?
or $
? The variable syntax introduced in the latest version of the IAM policy language includes escape sequences for this eventuality:
${*}
- use where you need an * (asterisk) character.${?}
- use where you need a ? (question mark) character.${$}
- use where you need a $ (dollar sign) character.
Valid Example:
"Condition": {"StringLike": {"aws:PrincipalTag/department": "sales${*}service"}}// would match a tag {"department": "sales*service"}