Cross-Account Encryption
Complete the full lesson to earn 25 points
Work through each section, then tap “Mark as Complete” on the last one.
✦ Skip the page breaks and see fewer ads — read each lesson on a single page with Pro
Lesson: Mastering Cross-Account Encryption
Introduction: The Challenge of Distributed Security
In modern cloud architecture, organizations rarely operate within a single, isolated environment. Instead, they distribute workloads across multiple accounts to maintain operational boundaries, improve security posture through blast-radius reduction, and satisfy compliance requirements. However, this architectural distribution introduces a significant complexity: how do you securely share encrypted data between these accounts without compromising the integrity of your cryptographic keys?
Cross-account encryption is the process of allowing an entity in one account (the "Requester") to encrypt or decrypt data using a cryptographic key stored and managed in a different account (the "Owner"). This is not merely a convenience feature; it is a fundamental requirement for secure data pipelines, centralized logging, and shared storage solutions. Without a structured approach to cross-account access, developers often resort to insecure practices like disabling encryption, copying raw keys between accounts, or creating overly permissive identity policies that expose sensitive data to unauthorized actors.
Understanding how to manage cross-account encryption requires a deep dive into the intersection of Identity and Access Management (IAM) and Key Management Services (KMS). This lesson will guide you through the mechanics of trust relationships, the dual-layered authorization model required for successful operations, and the practical implementation strategies that ensure your data remains protected even as it moves across administrative boundaries.
The Dual-Layered Authorization Model
To understand cross-account encryption, you must first understand that access control is not a single gateway. When an application in Account A attempts to use a key in Account B, the request must pass two distinct "checks." If either check fails, the operation is denied. This is a critical security feature designed to prevent accidental or malicious exposure of cryptographic resources.
1. The Key Policy (Resource-Based Policy)
The Key Policy resides in the account that owns the KMS key. It acts as the primary gatekeeper. Even if an IAM user in Account A has full administrative permissions, they cannot use a key in Account B unless the policy attached to that key explicitly permits it. The Key Policy must contain a statement that identifies the external principal (the user or role in Account A) and grants them specific actions, such as kms:Encrypt or kms:Decrypt.
2. The IAM Policy (Identity-Based Policy)
The second layer is the IAM policy attached to the user or role in the Requester's account (Account A). Even if the Key Policy in Account B grants access to the identity in Account A, the identity itself must have the permission to perform the action. If the IAM role in Account A lacks the kms:Decrypt permission for the specific key ARN in Account B, the operation will be rejected. This "double-check" ensures that you cannot inadvertently grant access to your keys unless the other party also explicitly authorizes their users to use them.
Callout: Principle of Least Privilege In cross-account scenarios, it is tempting to use wildcards (*) in your policies to "make it work." This is a dangerous practice. Always restrict your resource policies to the specific ARN of the key and your IAM policies to the specific actions required. By limiting the scope, you ensure that even if a credential is compromised, the attacker cannot pivot to other cryptographic assets in your environment.
Practical Implementation: A Step-by-Step Guide
Let us walk through a concrete scenario. Suppose you have a "Security Account" (Account 123456789012) that hosts a central KMS key, and a "Production Account" (Account 987654321098) that needs to encrypt logs before sending them to a shared S3 bucket.
Step 1: Configure the Key Policy in the Security Account
The owner of the key must modify the Key Policy to trust the specific IAM role in the Production Account. You should not use the root user for this; instead, target the specific role ARN.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCrossAccountUse",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::987654321098:role/LogWriterRole"
},
"Action": [
"kms:Encrypt",
"kms:GenerateDataKey",
"kms:DescribeKey"
],
"Resource": "*"
}
]
}
Step 2: Configure the IAM Policy in the Production Account
Now, the administrator of the Production Account must ensure that the LogWriterRole has the necessary permissions to call the KMS API in the Security Account.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowKMSAccessInSecurityAccount",
"Effect": "Allow",
"Action": [
"kms:Encrypt",
"kms:GenerateDataKey",
"kms:DescribeKey"
],
"Resource": "arn:aws:kms:us-east-1:123456789012:key/your-key-id-here"
}
]
}
Step 3: Performing the Operation
With both policies in place, the application code in the Production Account can now perform encryption. Because the key exists in a different account, the code must explicitly reference the key's full ARN rather than an alias.
import boto3
# Initialize the KMS client
kms = boto3.client('kms', region_name='us-east-1')
# The key ARN belongs to the Security Account
key_arn = 'arn:aws:kms:us-east-1:123456789012:key/your-key-id-here'
# Encrypt data
response = kms.encrypt(
KeyId=key_arn,
Plaintext=b'Secret information to be stored'
)
encrypted_data = response['CiphertextBlob']
print(f"Data encrypted successfully using cross-account key.")
Comparing Symmetric vs. Asymmetric Keys in Cross-Account Contexts
When dealing with cross-account encryption, the type of key you choose significantly impacts your architectural design.
| Feature | Symmetric Keys | Asymmetric Keys |
|---|---|---|
| Primary Use Case | Bulk data encryption/decryption | Secure data exchange, digital signatures |
| Cross-Account Complexity | Requires shared access to the KMS service | Can share public keys for local encryption |
| Performance | High; handled entirely by KMS | Slower; limited by payload size |
| Trust Model | Direct API access to KMS | Distribution of public key material |
Symmetric Keys
Symmetric keys are the standard for most cross-account operations. The Requester calls the KMS API, sending data to be encrypted or decrypted. The KMS service performs the cryptographic operation and returns the result. This is highly secure because the plaintext never leaves the KMS environment, but it does require the Requester to have network access to the KMS endpoint in the Owner's account.
Asymmetric Keys
Asymmetric keys allow for a different pattern. You can export the public portion of an asymmetric key and share it with other accounts. Those accounts can then perform encryption locally without calling the KMS service in the Owner's account. Decryption, however, still requires access to the private key, which never leaves the KMS module. This is useful for high-throughput scenarios where you want to avoid the latency or API limits of calling KMS for every transaction.
Note: When using asymmetric keys, ensure that the public key you distribute is verified. If an attacker replaces your public key with their own, they could potentially perform a man-in-the-middle attack. Always store public keys in a secure, version-controlled repository or a central secret manager.
Best Practices for Cross-Account Security
Managing cryptographic keys across boundaries is a high-stakes responsibility. Follow these industry-standard practices to minimize risk:
- Use Key Aliases Carefully: Do not rely on aliases for cross-account operations. Aliases are account-specific and can be changed. Always reference the Key ARN to ensure you are interacting with the intended resource.
- Audit with CloudTrail: Enable logging in both the Requester and the Owner accounts. In the Owner account, look for
kms:Decryptrequests coming from the external account ID. This provides a clear audit trail of who is accessing your data and when. - Avoid Key Sharing for Non-Essential Data: Just because you can share a key doesn't mean you should. If two accounts have entirely different security requirements, consider creating separate keys for each. Only use cross-account encryption when there is a clear business need for shared data access.
- Implement Periodic Key Rotation: AWS allows for automatic yearly rotation of KMS keys. Ensure this is enabled for your cross-account keys. Rotation does not require you to update your application code, as KMS maintains access to previous key versions for decryption.
- Monitor for Unauthorized Access Attempts: Set up alerts in your Security Account that trigger whenever a
AccessDeniederror occurs in KMS. This is often an early indicator of a misconfiguration or a potential probing attempt by a compromised identity.
Common Pitfalls and How to Avoid Them
Even experienced engineers frequently encounter issues when configuring cross-account encryption. Here are the most frequent mistakes:
1. The "Resource Not Found" Error
This often happens because the developer is using an alias (e.g., alias/my-key) instead of the full ARN. KMS aliases are local to the account; if you try to use an alias in a cross-account API call, the system will look for that alias in the Requester's account, fail to find it, and return an error.
- Fix: Always use the full
arn:aws:kms:region:account-id:key/key-idformat.
2. Forgetting the IAM Policy
It is common to meticulously configure the Key Policy in the Owner account and then forget to grant the corresponding permissions to the role in the Requester account. The request will fail with an "Access Denied" error, which can be frustrating because the error message does not always specify which policy is blocking the request.
- Fix: Use the Policy Simulator tool or check the CloudTrail logs, which will explicitly state if the denial originated from the IAM policy or the Key Policy.
3. Over-granting Permissions
Granting kms:* to an external account is a major security risk. It allows the external account to delete the key, disable it, or change its policy.
- Fix: Explicitly list only the actions required. For most data processing pipelines,
kms:Encrypt,kms:Decrypt, andkms:GenerateDataKeyare more than sufficient. Never grant administrative permissions to an external account.
4. Regional Mismatch
KMS keys are regional. You cannot encrypt data in us-east-1 using a key located in us-west-2. While this seems obvious, it often causes issues in automated deployment scripts where region variables might be misconfigured.
- Fix: Ensure that your infrastructure-as-code templates explicitly map the key region to the application deployment region.
Callout: Key Policy vs. IAM Policy Nuance A common point of confusion is the difference between "Key Policy" and "IAM Policy." Think of the Key Policy as the "Access Control List" (ACL) for the object, while the IAM Policy is the "Permission Set" for the user. Both must agree for the action to succeed. If you find yourself struggling with a permission error, create a table mapping the specific action to both policies to ensure no gaps exist.
Advanced Topic: Encrypting Data at Rest with S3 Cross-Account Access
A frequent real-world use case is writing encrypted files to an S3 bucket in a different account. This requires a three-way trust relationship:
- The KMS Key Policy: Must allow the Requester's IAM role to use the key.
- The S3 Bucket Policy: Must allow the Requester's IAM role to perform
s3:PutObject. - The IAM Policy: Must allow the Requester to perform both the KMS actions and the S3 actions.
When you perform a PutObject request to S3 with encryption enabled, S3 calls KMS on your behalf. If you are using a cross-account key, you must ensure the bucket policy explicitly allows the service to interact with that specific key. This is a common failure point; users often grant S3 permissions but forget that S3 needs its own permission to use the KMS key to finish the encryption process.
Code Example: Writing to a Cross-Account Bucket
# The Requester's account code
s3 = boto3.client('s3')
# Encrypting before sending, or letting S3 do it
# If letting S3 do it, you must provide the KMS Key ID in the request
s3.put_object(
Bucket='shared-bucket-in-other-account',
Key='data/logs.txt',
Body='Sensitive log data',
ServerSideEncryption='aws:kms',
SSEKMSKeyId='arn:aws:kms:us-east-1:123456789012:key/your-key-id-here'
)
In this example, the SSEKMSKeyId parameter is the bridge. S3 will use this ID to request an encryption key from the Security Account's KMS. The request will only succeed if the Security Account's key policy trusts the S3 service principal in the Requester's account or the Requester's IAM role, depending on how you've configured the bucket encryption settings.
Troubleshooting Checklist
When you find yourself stuck, follow this systematic approach to identify the failure:
- Check the CloudTrail Event: Look for the specific
ErrorCodein the event log.AccessDeniedis the most common. - Verify the Principal: Does the Key Policy specifically name the role ARN of the Requester? Ensure no typos in the account ID or role name.
- Check the Resource ARN: Are you using the full ARN in your IAM policy? Ensure the account ID in the ARN matches the account where the key resides.
- Confirm Region: Is the KMS client initialized in the same region as the key?
- Check for Service-Linked Roles: If using a service like S3 or Lambda, ensure the service-linked role has the necessary permissions in the Key Policy.
- Test with the CLI: Use the AWS CLI with the
--profileflag to mimic the Requester's identity and run akms:DescribeKeycommand. This is often faster than debugging application code.
Architectural Considerations for Scalability
As your organization grows, managing individual key policies for every cross-account interaction becomes unsustainable. Instead of granting access to every specific role, consider using IAM Role Chaining or Cross-Account Roles.
By creating a dedicated "Encryption Service Role" in the Security Account, you can allow other accounts to "assume" that role. The role itself contains the permissions to use the KMS keys. This centralizes your security logic; instead of updating fifty different key policies, you only update the trust relationship of the single "Encryption Service Role."
This approach also simplifies auditing. You can look at the logs for that specific role and see exactly which accounts are assuming it to perform encryption tasks. It turns a distributed, messy configuration into a centralized, manageable service.
Warning: Be cautious with role chaining. While it simplifies administration, it also creates a single point of failure. If the "Encryption Service Role" is compromised, an attacker could potentially gain access to all the keys that role is permitted to use. Always implement strict session policies and use condition keys (like
aws:PrincipalOrgID) to ensure only accounts within your organization can assume the role.
Summary and Key Takeaways
Cross-account encryption is a foundational skill for any cloud practitioner. It allows for the secure, distributed management of data while maintaining the strict boundaries necessary for enterprise-grade security. By understanding the dual-layered authorization model and the specific requirements for key policies and IAM policies, you can design systems that are both highly secure and operationally efficient.
Key Takeaways for Your Security Toolkit:
- Dual-Authorization is Mandatory: Always remember that access requires both a Key Policy (resource-side) and an IAM Policy (identity-side). Neither is sufficient on its own.
- Always Reference the ARN: Avoid aliases when working across accounts. The Key ARN is the only reliable way to ensure you are connecting to the correct cryptographic resource.
- Audit Everything: Use CloudTrail to monitor cross-account access. Treat
AccessDeniedevents as potential security signals rather than just configuration bugs. - Use the Principle of Least Privilege: Never use wildcards in your policies. Explicitly define the actions and resources to limit the scope of potential impact.
- Prefer Centralization for Scale: As your environment grows, move toward a centralized role-based model to avoid "policy sprawl" and simplify your security governance.
- Test Connectivity Early: Use the AWS CLI to verify your permissions before writing complex application logic. It saves hours of debugging time by isolating the infrastructure configuration from the code.
- Understand Service Interaction: Remember that services like S3, Lambda, and Glue need their own permissions to use KMS keys. Your user's permissions are not enough if the service itself is the one performing the encryption.
By mastering these concepts, you move from simply "making things work" to building resilient, professional-grade security architectures that protect your most valuable asset: your data. Whether you are building a data lake, a shared logging pipeline, or a multi-tenant application, the principles of cross-account encryption remain your strongest defense against unauthorized access.
Continue the course
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles your daily points limit so you progress twice as fast, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× daily points limit
- ✓ Distraction-free lessons