Use Case: Enforcing Data Encryption and Security Compliance with Tag-Based KMS Access Control¶
Overview¶
Implement comprehensive data encryption governance and security compliance by using tag-based access control for AWS KMS encryption keys. This use case demonstrates how TagOps combined with KMS key policies, IAM policies, Resource Control Policies (RCPs), and Service Control Policies (SCPs) can enforce encryption standards and prevent unauthorized access to sensitive data.
Problem Statement¶
Organizations managing sensitive data face critical security challenges:
- Ensuring all data at rest and in transit is encrypted with approved encryption keys
- Preventing unauthorized access to encryption keys used for sensitive data
- Enforcing data classification and encryption compliance across multiple teams and projects
- Difficulty auditing which resources are encrypted and with which keys
- Risk of data exposure due to misconfigured encryption or key policies
- Compliance requirements (HIPAA, PCI-DSS, SOC 2, GDPR) demanding strict encryption controls
Without tag-based encryption governance, organizations struggle to enforce consistent security policies, maintain compliance, and prevent data breaches resulting from improper key management.
Because AWS tag keys and values are case-sensitive (e.g., CostCenter, costcenter, and CostCenter are separate tags), inconsistent application of tags fragments data, leading to unreliable cost and operational outputs. Resources may be created without mandatory tags, resulting in non-compliance with internal or external standards.
Solution Overview¶
By implementing a tag-based encryption framework using TagOps, AWS KMS, IAM policies, RCPs, and SCPs, organizations can:
- Enforce automatic encryption of resources based on data classification tags
- Restrict KMS key usage to authorized principals and departments using tag-based ABAC
- Prevent cross-department access to encryption keys
- Ensure compliance with security frameworks through automated tag enforcement
- Audit encryption coverage and key usage patterns
- Implement defense-in-depth with multiple layers of tag-based policy enforcement
TagOps ensures all resources and KMS keys are properly tagged with classification and ownership metadata, enabling granular encryption access control.
All tags created via TagOps will have the exact same value - the risk of inconsistent tagging is much lower. In addition, if any tag is deleted from the resource but still exists in 1 of TagOps policies, TagOps will re-apply the tag back to the resource, this contributes to tag reliability.
Prerequisites¶
- AWS KMS permissions (create/manage keys, key policies, grants)
- IAM permissions to create and attach policies to roles/users
- AWS Organizations with RCPs and SCPs enabled (for organization-wide enforcement)
- Comprehensive data classification schema defined
- TagOps deployed and configured
- Understanding of compliance requirements (HIPAA, PCI-DSS, etc.)
- CloudTrail enabled for KMS key usage auditing
Step-by-Step Implementation¶
1. Define Data Classification and Security Tag Schema¶
Establish standardized tags for data classification and encryption governance:
Data Classification Tags:
DataClassification: "Public", "Internal", "Confidential", "Restricted"ComplianceScope: "PCI", "HIPAA", "SOC2", "GDPR", "None"Department: "Engineering", "Finance", "HR", "Legal"Owner: Email or team nameEncryptionRequired: "true", "false"
KMS Key Tags:
KeyPurpose: "Database", "S3", "EBS", "Secrets", "General"DataClassification: "Confidential", "Restricted"Department: Department authorized to use the keyComplianceScope: Compliance framework the key supports
2. Create KMS Keys Based on Department and Data Classification¶
Create Department-Specific KMS Keys:
# Create KMS key for Finance department - Restricted data
aws kms create-key \
--description "Finance Department - Restricted Data Encryption Key" \
--key-policy file://finance-key-policy.json
# Create KMS key for HR department - Confidential data
aws kms create-key \
--description "HR Department - Confidential Data Encryption Key" \
--key-policy file://hr-key-policy.json
# Create KMS key for Engineering - Internal data
aws kms create-key \
--description "Engineering Department - Internal Data Encryption Key" \
--key-policy file://engineering-key-policy.json
Note: After creating KMS keys, TagOps will automatically apply the appropriate tags (Department, DataClassification, ComplianceScope, KeyPurpose) based on your configured TagOps rules. Alternatively, you can manually tag KMS keys if needed, but TagOps automation is recommended for consistency.
3. Tag IAM Principals with Department and Data Access Level¶
Tag IAM Roles and Users:
# Tag IAM role for Finance team members
aws iam tag-role \
--role-name FinanceTeamRole \
--tags Key=Department,Value=Finance \
Key=DataAccessLevel,Value=Restricted
# Tag IAM role for HR team members
aws iam tag-role \
--role-name HRTeamRole \
--tags Key=Department,Value=HR \
Key=DataAccessLevel,Value=Confidential
# Tag IAM user
aws iam tag-user \
--user-name john.doe \
--tags Key=Department,Value=Engineering \
Key=DataAccessLevel,Value=Internal
4. Create Tag-Based IAM Policies for KMS Access Control¶
IAM Policy: Allow KMS Key Usage Only for Matching Department
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowKMSUsageForDepartmentMatch",
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey",
"kms:GenerateDataKeyWithoutPlaintext",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Department": "${aws:PrincipalTag/Department}"
}
}
},
{
"Sid": "DenyKMSUsageForOtherDepartments",
"Effect": "Deny",
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:ResourceTag/Department": "${aws:PrincipalTag/Department}"
}
}
}
]
}
IAM Policy: Restrict Key Access Based on Data Classification
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowRestrictedDataAccessForAuthorizedPrincipals",
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/DataClassification": "Restricted",
"aws:PrincipalTag/DataAccessLevel": "Restricted"
}
}
},
{
"Sid": "DenyRestrictedDataAccessForUnauthorized",
"Effect": "Deny",
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/DataClassification": "Restricted"
},
"StringNotEquals": {
"aws:PrincipalTag/DataAccessLevel": "Restricted"
}
}
}
]
}
5. Configure KMS Key Policies with Tag-Based Conditions¶
finance-key-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow Finance Department to Use Key",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalTag/Department": "Finance"
}
}
},
{
"Sid": "Deny Access from Other Departments",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalTag/Department": "Finance"
},
"Null": {
"aws:PrincipalTag/Department": "false"
}
}
}
]
}
6. Implement Service Control Policies (SCPs) for Encryption Enforcement¶
SCP: Deny Resource Creation Without Encryption
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyS3BucketCreationWithoutEncryption",
"Effect": "Deny",
"Action": "s3:CreateBucket",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
},
{
"Sid": "DenyEBSVolumeWithoutEncryption",
"Effect": "Deny",
"Action": "ec2:CreateVolume",
"Resource": "*",
"Condition": {
"Bool": {
"ec2:Encrypted": "false"
}
}
},
{
"Sid": "DenyRDSWithoutEncryption",
"Effect": "Deny",
"Action": [
"rds:CreateDBInstance",
"rds:CreateDBCluster"
],
"Resource": "*",
"Condition": {
"Bool": {
"rds:StorageEncrypted": "false"
}
}
},
{
"Sid": "EnforceKMSEncryptionForRestrictedData",
"Effect": "Deny",
"Action": [
"s3:PutObject",
"rds:CreateDBInstance",
"ec2:RunInstances"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/DataClassification": "Restricted"
},
"StringNotEquals": {
"aws:RequestTag/EncryptionKey": "arn:aws:kms:*:*:key/*"
}
}
}
]
}
SCP: Prevent Tag Modification on Encryption Keys
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyKMSTagModification",
"Effect": "Deny",
"Action": [
"kms:TagResource",
"kms:UntagResource"
],
"Resource": "*",
"Condition": {
"ForAnyValue:StringEquals": {
"aws:TagKeys": ["Department", "DataClassification", "ComplianceScope"]
}
}
}
]
}
7. Implement Resource Control Policies (RCPs) for Cross-Account Encryption Protection¶
RCP: Enforce Organization-Only Access to KMS Keys
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceOrgIdentitiesForKMS",
"Effect": "Deny",
"Principal": "*",
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey*",
"kms:CreateGrant"
],
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"aws:PrincipalOrgID": "o-yourorgid"
},
"BoolIfExists": {
"aws:PrincipalIsAWSService": "false"
}
}
}
]
}
RCP: Restrict S3 Object Encryption to Approved KMS Keys
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceApprovedKMSKeysForS3",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "*",
"Condition": {
"StringEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
},
"StringNotLike": {
"s3:x-amz-server-side-encryption-aws-kms-key-id": "arn:aws:kms:*:*:key/*"
},
"ArnNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::*:role/AdminRole"
}
}
}
]
}
8. Configure TagOps Rules for Encryption Tag Enforcement¶
Create TagOps rules to automatically tag resources with data classification and encryption metadata. TagOps rules cannot enforce encryption itself, but they can ensure all resources are properly tagged for compliance tracking.
TagOps Rule Configuration:
{
"rules": {
"EnforceDataClassificationTags": {
"name": "EnforceDataClassificationTags",
"description": "Tag S3, RDS, EBS volumes, DynamoDB, and Secrets Manager resources with data classification",
"category": "security",
"enabled": true,
"priority": 1,
"rule": {
"type": "template",
"templateName": "DataClassificationTemplate",
"tags": []
},
"condition": [
{
"type": "serviceResourceType",
"operator": "isIn",
"value": ["s3", "rds", "ec2", "dynamodb", "secretsmanager"]
}
],
"conditionOperation": "single"
},
"TagFinanceResources": {
"name": "TagFinanceResources",
"description": "Tag Finance department resources with restricted data classification",
"category": "security",
"enabled": true,
"priority": 2,
"rule": {
"type": "add",
"tags": [
{
"Department": "Finance"
},
{
"DataClassification": "Restricted"
},
{
"ComplianceScope": "PCI"
},
{
"EncryptionRequired": "true"
}
]
},
"condition": [
{
"type": "tagKeyValue",
"operator": "equal",
"value": "Department=Finance"
}
],
"conditionOperation": "single"
},
"TagKMSKeys": {
"name": "TagKMSKeys",
"description": "Tag KMS keys with department and classification metadata",
"category": "security",
"enabled": true,
"priority": 3,
"rule": {
"type": "add",
"tags": [
{
"KeyPurpose": "Database"
},
{
"DataClassification": "Confidential"
},
{
"ComplianceScope": "HIPAA"
}
]
},
"condition": [
{
"type": "serviceResourceType",
"operator": "equal",
"value": "kms"
}
],
"conditionOperation": "single"
},
"TagResourcesByName": {
"name": "TagResourcesByName",
"description": "Tag resources with 'finance' in name as restricted data",
"category": "security",
"enabled": true,
"priority": 4,
"rule": {
"type": "template",
"templateName": "RestrictedDataTemplate",
"tags": []
},
"condition": [
{
"type": "name",
"operator": "contains",
"value": "finance"
}
],
"conditionOperation": "single"
}
},
"templates": {
"DataClassificationTemplate": {
"name": "DataClassificationTemplate",
"description": "Standard data classification and encryption tags",
"category": "security",
"generalTags": ["createdBy", "creationDate", "region", "accountId"],
"constantTags": [
{
"DataClassification": "Internal"
},
{
"EncryptionRequired": "true"
}
]
},
"RestrictedDataTemplate": {
"name": "RestrictedDataTemplate",
"description": "Tags for restricted/sensitive data",
"category": "security",
"generalTags": ["createdBy", "creationDate"],
"constantTags": [
{
"DataClassification": "Restricted"
},
{
"EncryptionRequired": "true"
},
{
"ComplianceScope": "PCI"
}
]
}
},
"metadata": {
"exportedAt": "2025-11-15T08:03:41.765Z",
"version": "1.0",
"totalRules": 4,
"totalTemplates": 2
}
}
Creating Rules in TagOps UI:
- Create Tag Templates:
- Navigate to Rules page → Templates tab
- Create
DataClassificationTemplatewith:- Constant tags:
DataClassification,EncryptionRequired - Dynamic tags:
createdBy,creationDate,region,accountId
- Constant tags:
-
Create
RestrictedDataTemplatewith:- Constant tags:
DataClassification=Restricted,EncryptionRequired=true,ComplianceScope=PCI
- Constant tags:
-
Create Rule 1: Enforce Data Classification Tags
- Basic Information: Name, description, category
security - Conditions: Service type is
s3,rds,ec2,dynamodb, orsecretsmanager - Actions: Apply template
DataClassificationTemplate -
Advanced: Priority
1, enabled -
Create Rule 2: Tag Finance Resources
- Conditions: Tag
DepartmentequalsFinance - Actions: Add tags
Department=Finance,DataClassification=Restricted,ComplianceScope=PCI,EncryptionRequired=true -
Advanced: Priority
2, enabled -
Create Rule 3: Tag KMS Keys
- Conditions: Service type is
kms - Actions: Add tags
KeyPurpose=Database,DataClassification=Confidential,ComplianceScope=HIPAA -
Advanced: Priority
3, enabled -
Create Rule 4: Tag Resources by Name
- Conditions: Resource name contains
finance - Actions: Apply template
RestrictedDataTemplate - Advanced: Priority
4, enabled
Note: TagOps rules ensure proper tagging for compliance tracking. Actual encryption enforcement must be configured separately using: - AWS Service Control Policies (SCPs) to require encryption at creation - AWS Config rules to detect unencrypted resources - IAM policies to restrict access to unencrypted resources - KMS key policies for encryption key access control
9. Tag Resources with Data Classification¶
TagOps will automatically tag resources with data classification tags based on the rules configured in step 8. When resources are created or discovered, TagOps applies the appropriate tags automatically.
For S3 Buckets: Create the bucket normally. TagOps will automatically apply data classification tags based on your rules:
# Create S3 bucket - TagOps will automatically apply tags
aws s3api create-bucket \
--bucket finance-customer-data \
--region us-east-1
For RDS Databases: Create the database normally. TagOps will automatically apply data classification tags based on your rules:
# Create RDS database - TagOps will automatically apply tags
aws rds create-db-instance \
--db-instance-identifier hr-employee-db \
--db-instance-class db.t3.micro \
--engine mysql \
--master-username admin \
--master-user-password YourPassword123
TagOps rules configured in step 8 will automatically tag these resources with the appropriate DataClassification, Department, ComplianceScope, and EncryptionRequired tags based on the resource type, name patterns, or other conditions you've defined.
10. Set Up Auditing and Compliance Monitoring¶
Enable CloudTrail for KMS Key Usage:
aws cloudtrail create-trail \
--name kms-usage-trail \
--s3-bucket-name kms-audit-logs \
--include-global-service-events \
--is-multi-region-trail
AWS Config Rules:
- encrypted-volumes: Ensure all EBS volumes are encrypted
- rds-storage-encrypted: Ensure RDS databases are encrypted
- s3-bucket-server-side-encryption-enabled: Ensure S3 buckets use encryption
- kms-cmk-not-scheduled-for-deletion: Prevent accidental key deletion
- Custom rule: Verify KMS keys have required tags
Configuration Examples¶
Combined IAM Policy for Department-Based KMS Access¶
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Department": "${aws:PrincipalTag/Department}",
"kms:EncryptionContext:Department": "${aws:PrincipalTag/Department}"
}
}
}
]
}
CloudWatch Log Insights Query for KMS Usage by Department¶
fields @timestamp, userIdentity.principalId, requestParameters.keyId, resources.0.tags.Department
| filter eventName = "Decrypt" or eventName = "GenerateDataKey"
| stats count() by resources.0.tags.Department
Verification¶
Verify KMS Key Tag-Based Access Control¶
- Attempt to use KMS key from a role with matching Department tag (should succeed)
- Attempt to use KMS key from a role with non-matching Department tag (should fail)
- Review CloudTrail logs for KMS access attempts and denials
Verify Encryption Enforcement¶
- Attempt to create S3 bucket without encryption (should fail due to SCP)
- Attempt to create RDS database without encryption (should fail due to SCP)
- Attempt to create EBS volume without encryption (should fail due to SCP)
Verify Tag Compliance¶
- Run AWS Config rules to check encryption compliance
- Use TagOps compliance dashboard to verify all resources have required tags
- Run Resource Groups Tag Editor search for untagged KMS keys or resources
Verify RCP Enforcement¶
- Attempt cross-account access to KMS key from outside organization (should fail)
- Verify AWS service access to KMS keys still works (CloudTrail, S3, etc.)
Best Practices¶
-
Implement Least Privilege: Grant only minimum required KMS permissions; use tag-based conditions to restrict access further
-
Separate Keys by Data Classification: Create distinct KMS keys for each data classification level and department
-
Protect Tag Integrity: Use SCPs to prevent modification/deletion of security-critical tags (Department, DataClassification)
-
Use Encryption Context: Add encryption context to KMS operations for additional security layer and auditability
-
Regular Key Rotation: Enable automatic key rotation for KMS keys; maintain tags through rotation
-
Audit KMS Usage: Continuously monitor CloudTrail logs for unauthorized access attempts and unusual patterns
-
Test Policies in Non-Production: Validate tag-based policies in development/test environments before production rollout
-
Document Key Usage: Maintain clear documentation of which keys are used for which data types and departments
-
Implement Defense in Depth: Use multiple layers (IAM policies, key policies, SCPs, RCPs) for comprehensive protection
-
Automate Compliance Checks: Use AWS Config, TagOps, and custom Lambda functions to continuously verify encryption compliance
Troubleshooting¶
Access Denied When Using KMS Key¶
- Issue: Principal cannot decrypt data despite having IAM permissions
- Solution:
- Verify principal has matching Department tag
- Check KMS key policy allows access for the principal's tags
- Verify principal tags are correctly set (case-sensitive)
- Review CloudTrail for detailed error message and conditions evaluated
Resources Created Without Encryption¶
- Issue: Resources being created without encryption despite SCP
- Solution:
- Verify SCP is attached to correct OU/account
- Check SCP syntax and conditions
- Ensure account is not exempt from SCP (management account)
- Review service-specific encryption requirements
KMS Key Tags Modified by Unauthorized Users¶
- Issue: Critical tags (Department, DataClassification) being changed
- Solution:
- Implement SCP to deny
kms:TagResourceandkms:UntagResourcefor protected tags - Restrict IAM permissions for tag modification
- Enable CloudWatch Events to alert on tag modifications
- Use AWS Config to detect and auto-remediate tag changes
Cross-Account Access Still Possible Despite RCP¶
- Issue: Principals from external accounts can still access KMS keys
- Solution:
- Verify RCP is enabled in AWS Organizations
- Check RCP is attached to root/OU/account
- Verify RCP syntax uses
aws:PrincipalOrgIDcorrectly - Ensure RCP is not overridden by overly permissive key policy
Performance Impact from Tag-Based Policies¶
- Issue: API calls slower due to tag evaluation
- Solution:
- Tag evaluation is typically minimal; review policy complexity
- Simplify condition logic where possible
- Cache frequently used tag values in application layer
- Consider using session tags for temporary access
Compliance Audit Failures¶
- Issue: Unable to prove all data is encrypted
- Solution:
- Use AWS Config rules to continuously check encryption status
- Generate compliance reports from Config aggregator
- Use TagOps reports to verify tagging coverage
- Implement automated remediation for non-compliant resources
Additional Resources¶
- AWS KMS Tag-Based Access Control: https://docs.aws.amazon.com/kms/latest/developerguide/tag-permissions.html
- AWS Resource Control Policies: https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html
- AWS Service Control Policies: https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html
- Encryption Best Practices: https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/protecting-data-at-rest.html