
August 17, 2026
10 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
You need to encrypt data with AWS KMS: Keys, Policies, Rotation because storing plaintext secrets or PII in databases is a liability that no amount of firewall rules can fix. For developers building compliance-sensitive applications like legal-tech portals or fintech platforms, AWS Key Management Service provides the cryptographic backbone required to meet regulatory standards without managing physical HSMs. This guide covers the practical implementation of customer-managed keys, least-privilege policies, and automated rotation schedules specifically for PHP and Laravel workloads running on AWS infrastructure.
How Do You Choose Between Symmetric and Asymmetric Keys When You Encrypt Data with AWS KMS?
Selecting the correct key type is the first architectural decision you make when you secure sensitive application data. AWS KMS supports both symmetric and asymmetric keys, but they serve fundamentally different purposes in a production web environment.
Symmetric keys (AES-256-GCM) are the default choice for application-level encryption. They use a single key for both encryption and decryption, making them ideal for database field encryption, file storage protection, and envelope encryption patterns. In my experience building legal-tech portals where client documents must be encrypted at rest, symmetric CMKs provide the performance characteristics needed for high-throughput Laravel applications. The AWS SDK handles the cryptographic operations efficiently, and the cost per API call remains predictable.
Asymmetric keys (RSA or ECC) serve specific use cases: digital signatures, certificate signing, or encrypting data outside AWS that only specific parties can decrypt. They are computationally expensive and rarely appropriate for general application data encryption. Unless you have a documented requirement for non-repudiation or external party verification, stick with symmetric keys.
Creating a Customer Managed Symmetric Key
AWS managed keys work for basic services, but any serious application requires Customer Managed Keys (CMKs) for auditability and policy control. Create one via CLI:
aws kms create-key \
--key-usage ENCRYPT_DECRYPT \
--key-spec SYMMETRIC_DEFAULT \
--description "Production app data encryption key" \
--tags TagKey=Environment,TagValue=Production \
--region ap-south-1 Record the returned KeyId and ARN immediately. Store these in your application configuration or Secrets Manager — never hardcode them in source files. On projects I've maintained across multiple environments, tagging keys by environment prevents catastrophic cross-environment access during deployments.
What Is Envelope Encryption and Why Does It Matter When You Encrypt Data with AWS KMS?
Envelope encryption is the pattern that makes AWS KMS viable for application data at scale. Instead of calling KMS for every record you encrypt (which would hit rate limits and destroy performance), you generate a unique data key locally, use it to encrypt your payload, then encrypt only that small data key with KMS.
This approach gives you three critical advantages:
- Performance: Bulk encryption happens locally using fast AES libraries; KMS calls occur only once per data key lifecycle
- Cost control: KMS API charges stay minimal regardless of data volume
- Security isolation: Compromising the encrypted data alone is useless without the KMS-protected data key
Implementing Envelope Encryption in Laravel
The AWS SDK for PHP v3.x integrates cleanly with Laravel 12. Install via Composer and configure credentials through IAM roles (never static keys in .env):
composer require aws/aws-sdk-php-laravel
// In a dedicated EncryptionService
use Aws\Kms\KmsClient;
use Illuminate\Support\Facades\Storage;
class DocumentEncryptionService
{
public function encryptDocument(string $plaintext, string $keyId): array
{
$kms = app(KmsClient::class);
// Step 1: Generate data key
$result = $kms->generateDataKey([
'KeyId' => $keyId,
'KeySpec' => 'AES_256',
]);
// Step 2: Encrypt locally using OpenSSL
$iv = random_bytes(12); // GCM nonce
$ciphertext = openssl_encrypt(
$plaintext,
'aes-256-gcm',
$result['Plaintext'],
OPENSSL_RAW_DATA,
$iv,
$tag
);
// Step 3: Return bundle (encrypted key + iv + tag + ciphertext)
return [
'encrypted_key' => base64_encode($result['CiphertextBlob']),
'iv' => base64_encode($iv),
'tag' => base64_encode($tag),
'ciphertext' => base64_encode($ciphertext),
];
}
} This pattern keeps KMS calls minimal while maintaining strong cryptographic guarantees. The plaintext data key exists only in memory during the operation and is never written to disk or logs.
How Do You Write Least-Privilege Key Policies When You Encrypt Data with AWS KMS?
Key policies are the primary authorization mechanism for CMKs. Unlike IAM policies which attach to users/roles, key policies attach directly to the key resource itself. Both must permit an action for it to succeed. This dual-control model is what makes KMS secure, but misconfiguring it is the most common failure mode I encounter during security audits.
A properly scoped key policy follows these principles:
- Always include the root account principal — removing it locks everyone out permanently, including AWS support
- Restrict to specific IAM roles — never grant wildcard principals except for the root account entry
- Limit actions to what's needed — application roles typically need only
kms:Encrypt,kms:Decrypt,kms:GenerateDataKey - Add condition keys for context — restrict by VPC endpoint, source IP, or request tags to prevent lateral movement
Production-Ready Key Policy Template
{
"Version": "2012-10-17",
"Id": "app-data-key-policy",
"Statement": [
{
"Sid": "EnableRootAccountAccess",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::123456789012:root"},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "AllowApplicationEncryption",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::123456789012:role/LaravelAppRole"},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:GenerateDataKey",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "secretsmanager.ap-south-1.amazonaws.com"
}
}
},
{
"Sid": "AllowAdminManagement",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::123456789012:role/DevOpsAdminRole"},
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
],
"Resource": "*"
}
]
} The kms:ViaService condition is particularly valuable. It ensures the key can only be used through specific AWS services, preventing direct API misuse even if credentials are compromised. For applications accessing S3 encrypted objects, add s3.ap-south-1.amazonaws.com to this list.
Common Policy Mistakes That Break Production
I've debugged several incidents caused by policy errors. Watch for these:
- Missing DescribeKey permission — many SDKs call this before encryption; omitting it causes silent failures
- Wrong region in ViaService — the service endpoint must match the key's region exactly
- Overly broad wildcards —
kms:*on non-admin roles defeats the purpose of CMKs - Forgetting cross-account access — if Lambda in Account B needs to decrypt data encrypted by Account A, both the key policy AND Account B's IAM policy must allow it
How Does Automatic Key Rotation Work When You Encrypt Data with AWS KMS?
Automatic rotation is one of KMS's strongest compliance features, but understanding its mechanics prevents dangerous assumptions. For symmetric CMKs, AWS generates new backing key material annually while preserving the same key ID and ARN. Your application code requires zero changes.
Critical Rotation Constraints
Not all keys support automatic rotation. Know the boundaries:
| Key Type | Auto-Rotation | Manual Rotation Method | Notes |
|---|---|---|---|
| Symmetric CMK | ✅ Annual | N/A | Default for most app encryption |
| Multi-Region Symmetric | ✅ Annual | N/A | All replicas rotate together |
| Asymmetric RSA/ECC | ❌ Never | Create new key + migrate | Requires application reconfiguration |
| HMAC Keys | ❌ Never | Create new key + migrate | Used for token signing, not encryption |
| AWS Managed Keys | ✅ Automatic | N/A | No user control over schedule |
For asymmetric keys requiring rotation, plan a migration strategy well in advance. This involves creating a new key, updating application configuration, re-encrypting existing data (or accepting dual-key periods), and eventually scheduling deletion of the old key. On legal-tech platforms handling signed documents, I've found that maintaining a key registry table mapping document IDs to their signing key version simplifies this significantly.
Enabling Rotation Safely
# Enable automatic rotation
aws kms enable-key-rotation --key-id mrk-abc123def456
# Verify status
aws kms get-key-rotation-status --key-id mrk-abc123def456
# Check next rotation date
aws kms describe-key --key-id mrk-abc123def456 \
--query 'KeyMetadata.NextRotationDate' Enable rotation immediately after key creation. There is no operational downside — old backing keys remain available indefinitely for decrypting historical data. Disabling rotation later does not delete previous versions; it simply stops generating new ones.
How Do You Integrate AWS KMS Encryption Into Laravel Applications Securely?
Integration extends beyond code. Infrastructure configuration determines whether your encryption actually protects data or just adds complexity. For teams evaluating cloud hosting versus traditional options, KMS availability often tips the scale toward AWS for regulated workloads.
IAM Role Configuration Over Static Credentials
Never store AWS access keys in .env files. EC2 instances and Lambda functions should assume IAM roles with minimal KMS permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource": "arn:aws:kms:ap-south-1:123456789012:key/mrk-abc123def456"
}
]
} This role grants only decryption capabilities — sufficient for reading encrypted records but preventing accidental or malicious encryption of new data with the wrong key. Separate roles for write-heavy services enforce separation of concerns.
Handling Decryption Failures Gracefully
KMS calls fail for legitimate reasons: throttling, network issues, disabled keys, or deleted keys. Your application must handle these explicitly:
- Throttling: Implement exponential backoff with jitter; KMS defaults to 12,000 requests/second per account but shared tenancy can cause bursts
- Disabled keys: Log the key ID and alert operations; this indicates intentional suspension requiring investigation
- Deleted keys: Data is unrecoverable after the waiting period expires; ensure monitoring catches scheduled deletions before completion
- Access denied: Verify IAM role assumptions and key policy conditions; test with
aws sts get-caller-identityto confirm assumed role
For high-throughput applications, consider caching decrypted data keys in Redis with short TTLs (minutes, not hours). This reduces KMS dependency during traffic spikes while maintaining reasonable security bounds. Always encrypt cached keys with a separate local master key stored in Secrets Manager.
Testing Encryption Without Production Risk
Use KMS key policies to create test-specific keys with relaxed conditions. Never test against production CMKs. AWS also provides local testing tools like aws-encryption-cli for offline validation of envelope encryption logic before deployment.
Secure Implementation Checklist for Encrypt Data with AWS KMS: Keys, Policies, Rotation
Successfully implementing encrypt data with AWS KMS: Keys, Policies, Rotation requires attention to detail across configuration, code, and operations. Start with symmetric customer-managed keys for application data unless you have documented requirements for asymmetric cryptography. Implement envelope encryption to avoid rate limits and excessive costs. Write key policies with explicit principals and restrictive conditions rather than permissive wildcards. Enable automatic rotation on day one for all eligible keys. Configure IAM roles instead of static credentials, and build robust error handling for KMS API failures.
These practices form the foundation of production-grade encryption that satisfies auditors while remaining maintainable by development teams. If you're building compliance-sensitive applications and need guidance on secure architecture, reach out to discuss your encryption requirements.

