In AWS, resource access is typically governed by IAM policies or resource-based policies. There are a few exceptions to this rule and some services support an access mechanism called grants. In AWS, S3 (either via ACL grants or S3 Access grants) and KMS (Key Management Service) both support grants. AWS KMS Keys are used to protect and encrypt data. With access to KMS keys, it's possible for applications and users to gain access to data.
For KMS Keys, access to keys (and potential data access) can be done by IAM policy, resource-based policies (KMS Key policies), and/or KMS key grants. Additionally, behavior of KMS-specific resource-based policies is atypical of other resource-based policies in AWS. Thus, KMS access can be complex.
Identity and Access is complex and we found the following data access combinations across IAM policies, resource-based policies, and KMS key grants. We'll look at access differently than what is typically shown to gain a better understanding of the possible access combinations and ways to provide data and encryption access via KMS keys.
We can then build on top of those minimum access combinations to get the following 27 total combinations (including the 9 minimum from above).
We'll cover the following interesting behavior and deep dive on access for KMS Keys:
We tested and listed all the potential combinations of access granted (in the absence of any explicit denies) for both evaluation within a single account and evaluation for a cross-account scenario. Cross-account scenario would be when the requesting principal exists in Account B and the KMS Key (resource) exists in Account A. in AWS, same account and cross-account scenarios can be evaluated differently.
We took AWS's access and characterized the following possible options for access. This simplifies AWS policy language and does not factor in conditions and other advanced policy pieces.
-
)The chart below contains the minimum required access. For these exercises, we see the explicit allow as the most powerful, then the delegation policy, then implicit allow. For example, an Explicit Allow in a KMS Key Grant created by a Caller Account and an explicit allow in the KMS Key Policy for a cross account use case would result in success since the minimum permissions would only need an Explicit Allow (created by a Caller Account) in the KMS Key Grant. We have the following 9 minimum access combinations: 4 for same account evaluation and 5 for cross account evaluation.
Note: Delegation in the above chart is a policy where an AWS Account identifier is specified in the Principal element. This delegates authority to the account when an administrator in that account must then grant access to an identity (IAM role or user) in that account. The delegation policy by itself does not grant access. For more information on delegation, see below section on KMS Key Policies and Delegation.
Now, let's look at all of the potential access combinations (not just the minimum). We found 27 access combinations: 13 for same account evaluation and 14 for cross account evaluation.
We can further split this into separate tables for same account evaluation and cross account evaluation.
Below is the potential combination of access with only KMS Key Policies and IAM Policies which is much less complex. We only have to look for the following:
Below is a table of testing access to kms:Decrypt via KMS Key Grants where we've modified the KMS Key Policy to reflect an implicit deny. This testing was done within an AWS Account as evaluation for single account has different logic than multi-account evaluation.
The 2 cases where access was permitted were with the KMS Key Grant having an explicit allow. Thus, a KMS Key Grant alone (in the absence of any deny policies) can permit access to the KMS key.
Our reference key policy that removes the default delegation (more on that later)
{
"Version": "2012-10-17",
"Id": "key-policy-test",
"Statement": [
{
"Sid": "Allow access for Root",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123412341234:root"
},
"Action": "kms:*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalType": "Account"
}
}
},
{
"Sid": "Allow access for Key Administrators",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123412341234:role/admin-role"
},
"Action": "kms:*",
"Resource": "*"
}
]
}
Below is a table of testing access to kms:Decrypt via KMS Key Grants where we've used the default key policy provided by AWS.
From comparing these results with earlier, an explicit allow in either the KMS Key Grant or the IAM Policy will result in access permitted.
Delegation occurs in resource-based policies when the AWS account identifier is specified in the Principal element. From AWS documentation, "This delegates authority to the account. When you allow access to a different account, an administrator in that account must then grant access to an identity (IAM user or role) in that account."
An example delegation policy is as follows:
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123412341234:root"
},
"Action": "kms:*",
"Resource": "*"
}
The above delegation policy does not grant access directly to any IAM user or role in the account. In KMS, the following is true:
The AWS-provided default KMS key policy changes the behavior of KMS access by allowing usage of IAM policies and thus "delegating" the ability to permit access to IAM policies. Without the delegation policy, the KMS key policy must explicitly allow access.
From AWS documentation on policy evaluation: "For most resources, you only need an explicit allow for the principal in either an identity-based policy or a resource-based policy to grant access. IAM Role Trust policies and KMS key policies are exceptions to this logic, because they must explicitly allow access for principals"
From AWS documentation on default key policies: "This default key policy has one policy statement that gives the AWS account that owns the KMS key permission to use IAM policies to allow access to all AWS KMS operations on the KMS key." and "When the principal in a key policy statement is the account principal, the policy statement doesn't give any IAM principal permission to use the KMS key. Instead, it allows the account to use IAM policies to delegate the permissions specified in the policy statement. This default key policy statement allows the account to use IAM policies to delegate permission for all actions (kms:*
) on the KMS key."
Below is our modified version of a key policy to still allow root access in case of lockout as well as adding access for a key administrator. To do so, we added a condition key for aws:PrincipalType
and matched that to Account.
{
"Version": "2012-10-17",
"Id": "key-policy-test",
"Statement": [
{
"Sid": "Allow access for Root",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123412341234:root"
},
"Action": "kms:*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalType": "Account"
}
}
},
{
"Sid": "Allow access for Key Administrators",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123412341234:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_AdministratorAccess"
},
"Action": "kms:*",
"Resource": "*"
}
]
}
KMS Key Grants may be a hidden avenue of data access as they're not auditable via the KMS Key Policy nor IAM Policies. Additionally, KMS Key Grants do not appear in the AWS Console and only can be found via the AWS CLI.
Additional points of interest with KMS Key Grants:
Recommendations
If you want to chat cloud encryption management and cloud data security, email us at info@fogsecurity.io, we'd love to hear from you. We're passionate about cloud data security and are building tools to help teams with identifying data access and securing data in your AWS-based workloads and infrastructure. More research and resources related to encryption and data perimeters to come!