Outdated Default AWS IAM Policy Language Versions
February 16, 2023
Overview
The AWS Identity and Access Management (IAM) service is used to securely control access to AWS resources and can be expressed in JSON as IAM policies (opens in a new tab). The Version
element of the JSON policy specifies which language syntax rules are used when processing the policy.
There are 2 possible Version
element values: 2012-10-17
and 2008-10-17
. The 2008-10-17
version is an earlier version that does not support newer features such as policy variables and AWS recommends not to use this version for any new policies or when updating existing policies. (opens in a new tab) After going through all services that support IAM resource-based policies and identity-based policies, we found multiple AWS services that used the legacy 2008-10-17
policy version, including Gateway VPC Endpoint Policies, SNS Topic Policies, and SQS Queue Policies.
We sent details on our research and our thoughts regarding developer experience on outdated policy versions and default behavior to the AWS Security team on February 8th, 2023. This came up as a discussion point in an AWS Security online community regarding SNS Topic policies and we did further research on other default and example policies across all AWS services.
In this post, we will cover the IAM Policy Language Version and what that means, our research on which services have default legacy versions, the user experience in AWS when specifying the policy version, how to find default legacy versions in your AWS environment, and recommendations.
IAM Policy Language Version
A lesser known detail about IAM policy grammar is the policy Version element
. This is not the different versions of IAM policies (opens in a new tab) that can be created for managed policies via CreatePolicyVersion
. We're referring to the snippet of "Version": "2008-10-17"
or "Version": "2012-10-17"
that may be included in an IAM policy. This Version
specifies which language syntax rules are used when processing the IAM policy.
In AWS console and even in the CLI/API, there are default and example policies that leverage the legacy interpretation of the IAM policy language which can create issues for developers. IAM is one of the building blocks in AWS and often can be a source of headaches for developers to properly configure permissions and access for applications, let alone focus on least privilege and properly defined IAM permissions. By using the legacy 2008-10-17
version of the policy language, this can lead to misconfiguration and development time spent troubleshooting differences in language syntax rules such as policy variables being treated as literal strings in the policy.
There are 3 different implicit and explicit settings for the Version
element:
- Explicit
2012-10-17
- Explicit
2008-10-17
- Implicit
2008-10-17
: NoVersion
specified.
The Version
element can be present in both identity-based policies and resource-based policies (opens in a new tab) among other policy types.
"Version": "2008-10-17",
"Id": "OutdatedVersionElement",
"Statement": [
{
"Sid": "ExampleStatement",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"SQS:ReceiveMessage"]
}
...
Identity-Based Policies and Their Versions
There are 4 types of identity-based policies that we will take a look at:
- IAM Customer Managed Policies (opens in a new tab)
- Inline IAM Group policies (opens in a new tab)
- Inline IAM User policies (opens in a new tab)
- Inline IAM Role policies (opens in a new tab)
AWS has controls that block the creation of IAM managed policies with legacy policy versions. The following screenshots show the mechanisms for blocking a policy created without 2012-10-17
specified in the policy version. In console, an error message pops up about the version string.
With the AWS CLI, we get a `MalformedPolicyDocument`` error:
However, these controls are inconsistent and do not apply to inline policies. Inline policies still can be created with legacy policy versions of 2008-10-17
or with no Version
specified.
We used the following JSON as our policy:
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "ListPolicies",
"Effect": "Allow",
"Action": [
"iam:ListPolicies"
],
"Resource": "*"
}
]
}
The following command to put an inline policy on our cloudquery-user
user succeeded:
aws iam put-user-policy \
--user-name cloudquery-user \
--policy-name test-cq-policy \
--policy-document file://2008policyversion.json
Finding Identity-Based Policies with CloudQuery
The below queries have a prerequisite to use CloudQuery to sync AWS data to PostgreSQL. For a guide, see our quickstart guide (opens in a new tab).
We will use CloudQuery to check for identity-based with 2008-10-17
explicitly set as the version or for identity-based policies without an explicit version set.
Finding IAM User Inline Policies
SELECT * FROM
(
SELECT policy_document ->> 'Version' as version, *
FROM aws_iam_user_policies
) as user_policies
WHERE version = '2008-10-17'
OR version is NULL;
Finding IAM Group Inline Policies
SELECT * FROM
(
SELECT policy_document ->> 'Version' as version, *
FROM aws_iam_group_policies
) as group_policies
WHERE version = '2008-10-17'
OR version is NULL;
Finding IAM Role Inline Policies
SELECT * FROM
(
SELECT policy_document ->> 'Version' as version, *
FROM aws_iam_role_policies
) as role_policies
WHERE version = '2008-10-17'
OR version is NULL;
Resource-Based Policies and Their Versions
In our research, we found 3 types of resource-based policies with default versions set to 2008-10-17
:
- AWS SQS Queues (opens in a new tab)
- AWS SNS Topics (opens in a new tab)
- AWS VPC Endpoints (Gateway Endpoint Policies only) (opens in a new tab)
The below table shows the AWS services we tested based on AWS Services that work with IAM (opens in a new tab). From our research, we found some services default to 2012-10-17
, some services default to 2008-10-17
, some services default to empty policies (Empty), and some services did not support writing full IAM policy JSON.
AWS Service | Default Policy Version Element | Comments |
---|---|---|
AWS SQS | 2008 | Both Console and API/CLI |
AWS SNS | 2008 | Both Console and API/CLI |
AWS VPC Endpoints | 2008 | Gateway Endpoints Only |
AWS VPC Endpoints | 2012 | Interface Endpoints (Did not test all Interface Endpoints) |
AWS Lambda | 2012 | Console |
AWS SES | 2012 | Console |
AWS Glue | Empty | Console |
AWS EFS | Empty | Console |
AWS KMS | 2012 | Console |
AWS Secrets Manager | 2012 | Console |
AWS ECR (Repository) | 2012 | Console |
AWS CloudWatch Logs | 2012 | API/CLI Only |
AWS S3 | 2012 | Console |
AWS IAM | 2012 | Console |
AWS Private CA | Unknown | API/CLI Only |
AWS API Gateway | 2012 | Console |
AWS Cloud9 | NA | Does not support full IAM Policy Language |
AWS SAM | NA | Does not support full IAM Policy Language |
AWS Backup | 2012 | Console |
AWS S3 Glacier | Empty | Console |
AWS S3 Outposts | Unknown | Did Not Test |
AWS CodeArtifact | 2012 | Console |
AWS Lex v2 | Empty | Console |
AWS OpenSearch | 2012 | Console |
AWS EventBridge Schemas | 2012 | Console |
AWS EventBridge Event Buses | 2012 | Console |
AWS Elemental MediaStore | 2012 | Console |
AWS CloudTrail | 2012 | Console |
Finding Resource-Based Policies with CloudQuery
We will use CloudQuery to check for resource-based policies with 2008-10-17
explicitly set as the version or for resource-based policies without an explicit version set. The following queries will be used to check for SQS queue policies, SNS topic policies, and VPC Endpoint policies. Additional queries can be written for other AWS resource-based policies.
Finding SQS Queues and Their Resource-Based Policies
SELECT * FROM
(
SELECT policy ->> 'Version' as version, *
FROM aws_sqs_queues
) as sqs_queues
WHERE version = '2008-10-17'
OR version is NULL;
Finding SNS Topics and Their Resource-Based Policies
SELECT * FROM
(
SELECT policy ->> 'Version' as version, *
FROM aws_sns_topics
) as sns_topics
WHERE version = '2008-10-17'
OR version is NULL;
Finding VPC Endpoints and Their Resource-Based Policies
SELECT * FROM
(
SELECT policy_document ->> 'Version' as version, *
FROM aws_vpc_endpoints
) as vpc_endpoints
WHERE version = '2008-10-17'
OR version is NULL;
Conclusion
The legacy policy version 2008-10-17
can be problematic for developers and application teams given the difference in interpretation by AWS.
We would like to see the following from AWS:
- Example and default policies should have default policy versions set to
2012-10-17
. - Not specifying a policy version should also default to
2012-10-17
once enough warning has been given to AWS customers. - In the interim, more controls similar to the IAM Managed Policy creation experience that block creation of new policies without
2012-10-17
specified.
In the interim, we have the following recommendations for AWS end users:
- Scan AWS environments for any legacy usage of the
2008-10-17
policy language version. - If possible, update legacy policies to use the
2012-10-17
policy language version. - Ensure all new policies leverage the newer
2012-10-17
policy language version.
Stay tuned for more use cases we can build with CloudQuery on top of the infrastructure data we loaded from AWS!
Contact Us
If you have comments or questions about IAM, CloudQuery, or potential partnerships with us, we would love to hear from you! Reach out to us on GitHub (opens in a new tab) or Discord (opens in a new tab)!
References and Useful Links
CloudQuery: AWS Plugin (opens in a new tab)
AWS: IAM JSON policy elements: Version (opens in a new tab)
AWS: Grammar of the IAM JSON Policy Language (opens in a new tab)
AWS: AWS Services that work with IAM (opens in a new tab)
AWS: IAM Policy elements: Variables and Tags (opens in a new tab)