aws-cis-controls-assessment 1.0.9__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aws_cis_assessment/__init__.py +2 -2
- aws_cis_assessment/config/rules/cis_controls_ig1.yaml +94 -1
- aws_cis_assessment/config/rules/cis_controls_ig2.yaml +680 -1
- aws_cis_assessment/controls/ig1/__init__.py +17 -0
- aws_cis_assessment/controls/ig1/control_aws_backup_service.py +1276 -0
- aws_cis_assessment/controls/ig2/__init__.py +74 -1
- aws_cis_assessment/controls/ig2/control_4_5_6_access_configuration.py +2638 -0
- aws_cis_assessment/controls/ig2/control_8_audit_logging.py +984 -0
- aws_cis_assessment/controls/ig2/control_aws_backup_ig2.py +23 -0
- aws_cis_assessment/core/assessment_engine.py +74 -0
- aws_cis_assessment/reporters/html_reporter.py +197 -35
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/METADATA +163 -12
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/RECORD +26 -21
- docs/README.md +14 -3
- docs/adding-aws-backup-controls.md +562 -0
- docs/assessment-logic.md +291 -3
- docs/cli-reference.md +1 -1
- docs/config-rule-mappings.md +465 -7
- docs/developer-guide.md +312 -3
- docs/installation.md +2 -2
- docs/troubleshooting.md +211 -2
- docs/user-guide.md +47 -2
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/WHEEL +0 -0
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/entry_points.txt +0 -0
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/top_level.txt +0 -0
docs/assessment-logic.md
CHANGED
|
@@ -5,7 +5,7 @@ This document provides detailed information about the assessment logic used by t
|
|
|
5
5
|
## Production Framework Overview
|
|
6
6
|
|
|
7
7
|
**✅ Complete Implementation Status**
|
|
8
|
-
-
|
|
8
|
+
- 138 AWS Config rules implemented (133 CIS Controls + 5 bonus)
|
|
9
9
|
- 100% coverage across all Implementation Groups (IG1, IG2, IG3)
|
|
10
10
|
- Production-tested with enterprise-grade error handling
|
|
11
11
|
- Optimized for large-scale enterprise deployments
|
|
@@ -25,7 +25,7 @@ This document provides detailed information about the assessment logic used by t
|
|
|
25
25
|
|
|
26
26
|
The assessment tool evaluates AWS account configurations against CIS Controls using the same logic as AWS Config rules, but without requiring AWS Config to be enabled. Each assessment follows a standardized process while implementing control-specific evaluation logic.
|
|
27
27
|
|
|
28
|
-
**Framework Scope**:
|
|
28
|
+
**Framework Scope**: 138 implemented rules covering all CIS Controls requirements plus 5 bonus security enhancements for additional value.
|
|
29
29
|
|
|
30
30
|
### Key Principles
|
|
31
31
|
|
|
@@ -763,4 +763,292 @@ def batch_evaluate_resources(self, resources, batch_size=50):
|
|
|
763
763
|
return results
|
|
764
764
|
```
|
|
765
765
|
|
|
766
|
-
This comprehensive assessment logic ensures accurate, efficient, and reliable evaluation of AWS resources against CIS Controls while maintaining compatibility with AWS Config rule specifications.
|
|
766
|
+
This comprehensive assessment logic ensures accurate, efficient, and reliable evaluation of AWS resources against CIS Controls while maintaining compatibility with AWS Config rule specifications.
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
### AWS Backup Resources
|
|
770
|
+
```python
|
|
771
|
+
def discover_backup_plans(self, backup_client, region):
|
|
772
|
+
"""Discover AWS Backup plans in specific region."""
|
|
773
|
+
try:
|
|
774
|
+
paginator = backup_client.get_paginator('list_backup_plans')
|
|
775
|
+
|
|
776
|
+
backup_plans = []
|
|
777
|
+
for page in paginator.paginate():
|
|
778
|
+
for plan in page['BackupPlansList']:
|
|
779
|
+
try:
|
|
780
|
+
# Get detailed plan information
|
|
781
|
+
plan_details = backup_client.get_backup_plan(
|
|
782
|
+
BackupPlanId=plan['BackupPlanId']
|
|
783
|
+
)
|
|
784
|
+
|
|
785
|
+
backup_plans.append({
|
|
786
|
+
'BackupPlanId': plan['BackupPlanId'],
|
|
787
|
+
'BackupPlanName': plan['BackupPlanName'],
|
|
788
|
+
'BackupPlanArn': plan['BackupPlanArn'],
|
|
789
|
+
'CreationDate': plan['CreationDate'],
|
|
790
|
+
'VersionId': plan['VersionId'],
|
|
791
|
+
'Rules': plan_details['BackupPlan'].get('Rules', []),
|
|
792
|
+
'Region': region
|
|
793
|
+
})
|
|
794
|
+
|
|
795
|
+
except ClientError as e:
|
|
796
|
+
# Skip plans we can't access
|
|
797
|
+
if e.response['Error']['Code'] in ['AccessDenied', 'ResourceNotFoundException']:
|
|
798
|
+
continue
|
|
799
|
+
raise
|
|
800
|
+
|
|
801
|
+
return backup_plans
|
|
802
|
+
|
|
803
|
+
except ClientError as e:
|
|
804
|
+
if e.response['Error']['Code'] == 'AccessDenied':
|
|
805
|
+
self.logger.warning(f"Insufficient permissions for Backup in {region}")
|
|
806
|
+
return []
|
|
807
|
+
raise
|
|
808
|
+
|
|
809
|
+
def discover_backup_vaults(self, backup_client, region):
|
|
810
|
+
"""Discover AWS Backup vaults in specific region."""
|
|
811
|
+
try:
|
|
812
|
+
paginator = backup_client.get_paginator('list_backup_vaults')
|
|
813
|
+
|
|
814
|
+
backup_vaults = []
|
|
815
|
+
for page in paginator.paginate():
|
|
816
|
+
for vault in page['BackupVaultList']:
|
|
817
|
+
try:
|
|
818
|
+
# Get vault access policy if exists
|
|
819
|
+
try:
|
|
820
|
+
policy_response = backup_client.get_backup_vault_access_policy(
|
|
821
|
+
BackupVaultName=vault['BackupVaultName']
|
|
822
|
+
)
|
|
823
|
+
vault['Policy'] = policy_response.get('Policy')
|
|
824
|
+
except ClientError as e:
|
|
825
|
+
if e.response['Error']['Code'] == 'ResourceNotFoundException':
|
|
826
|
+
vault['Policy'] = None
|
|
827
|
+
else:
|
|
828
|
+
raise
|
|
829
|
+
|
|
830
|
+
backup_vaults.append({
|
|
831
|
+
'BackupVaultName': vault['BackupVaultName'],
|
|
832
|
+
'BackupVaultArn': vault['BackupVaultArn'],
|
|
833
|
+
'CreationDate': vault['CreationDate'],
|
|
834
|
+
'EncryptionKeyArn': vault.get('EncryptionKeyArn'),
|
|
835
|
+
'NumberOfRecoveryPoints': vault.get('NumberOfRecoveryPoints', 0),
|
|
836
|
+
'Policy': vault.get('Policy'),
|
|
837
|
+
'Region': region
|
|
838
|
+
})
|
|
839
|
+
|
|
840
|
+
except ClientError as e:
|
|
841
|
+
if e.response['Error']['Code'] in ['AccessDenied', 'ResourceNotFoundException']:
|
|
842
|
+
continue
|
|
843
|
+
raise
|
|
844
|
+
|
|
845
|
+
return backup_vaults
|
|
846
|
+
|
|
847
|
+
except ClientError as e:
|
|
848
|
+
if e.response['Error']['Code'] == 'AccessDenied':
|
|
849
|
+
self.logger.warning(f"Insufficient permissions for Backup vaults in {region}")
|
|
850
|
+
return []
|
|
851
|
+
raise
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
## AWS Backup Controls Logic
|
|
855
|
+
|
|
856
|
+
### Backup Plan Frequency and Retention Check
|
|
857
|
+
|
|
858
|
+
Evaluates backup plans to ensure they meet minimum frequency and retention requirements:
|
|
859
|
+
|
|
860
|
+
```python
|
|
861
|
+
def evaluate_backup_plan_compliance(self, resource, aws_factory):
|
|
862
|
+
"""Evaluate backup plan frequency and retention requirements."""
|
|
863
|
+
backup_plan_id = resource['BackupPlanId']
|
|
864
|
+
backup_plan_name = resource['BackupPlanName']
|
|
865
|
+
rules = resource.get('Rules', [])
|
|
866
|
+
region = resource['Region']
|
|
867
|
+
|
|
868
|
+
if not rules:
|
|
869
|
+
return ComplianceResult(
|
|
870
|
+
resource_id=backup_plan_id,
|
|
871
|
+
resource_type="AWS::Backup::BackupPlan",
|
|
872
|
+
compliance_status="NON_COMPLIANT",
|
|
873
|
+
evaluation_reason="Backup plan has no rules defined",
|
|
874
|
+
config_rule_name="backup-plan-min-frequency-and-min-retention-check",
|
|
875
|
+
region=region,
|
|
876
|
+
timestamp=datetime.now(),
|
|
877
|
+
remediation_guidance="Add backup rules with appropriate frequency and retention"
|
|
878
|
+
)
|
|
879
|
+
|
|
880
|
+
# Check each rule for compliance
|
|
881
|
+
non_compliant_rules = []
|
|
882
|
+
|
|
883
|
+
for rule in rules:
|
|
884
|
+
rule_name = rule.get('RuleName', 'Unnamed')
|
|
885
|
+
|
|
886
|
+
# Check frequency (schedule expression)
|
|
887
|
+
schedule = rule.get('ScheduleExpression', '')
|
|
888
|
+
if not self._meets_frequency_requirement(schedule):
|
|
889
|
+
non_compliant_rules.append(
|
|
890
|
+
f"{rule_name}: frequency does not meet minimum (daily)"
|
|
891
|
+
)
|
|
892
|
+
|
|
893
|
+
# Check retention (minimum 35 days / 5 weeks)
|
|
894
|
+
lifecycle = rule.get('Lifecycle', {})
|
|
895
|
+
delete_after_days = lifecycle.get('DeleteAfterDays')
|
|
896
|
+
|
|
897
|
+
if delete_after_days is None or delete_after_days < 35:
|
|
898
|
+
non_compliant_rules.append(
|
|
899
|
+
f"{rule_name}: retention {delete_after_days} days is less than minimum (35 days)"
|
|
900
|
+
)
|
|
901
|
+
|
|
902
|
+
if non_compliant_rules:
|
|
903
|
+
return ComplianceResult(
|
|
904
|
+
resource_id=backup_plan_id,
|
|
905
|
+
resource_type="AWS::Backup::BackupPlan",
|
|
906
|
+
compliance_status="NON_COMPLIANT",
|
|
907
|
+
evaluation_reason=f"Backup plan rules do not meet requirements: {'; '.join(non_compliant_rules)}",
|
|
908
|
+
config_rule_name="backup-plan-min-frequency-and-min-retention-check",
|
|
909
|
+
region=region,
|
|
910
|
+
timestamp=datetime.now(),
|
|
911
|
+
remediation_guidance="Update backup plan rules to meet minimum frequency (daily) and retention (35 days)"
|
|
912
|
+
)
|
|
913
|
+
|
|
914
|
+
return ComplianceResult(
|
|
915
|
+
resource_id=backup_plan_id,
|
|
916
|
+
resource_type="AWS::Backup::BackupPlan",
|
|
917
|
+
compliance_status="COMPLIANT",
|
|
918
|
+
evaluation_reason="Backup plan meets frequency and retention requirements",
|
|
919
|
+
config_rule_name="backup-plan-min-frequency-and-min-retention-check",
|
|
920
|
+
region=region,
|
|
921
|
+
timestamp=datetime.now()
|
|
922
|
+
)
|
|
923
|
+
|
|
924
|
+
def _meets_frequency_requirement(self, schedule_expression):
|
|
925
|
+
"""Check if schedule expression meets minimum daily frequency."""
|
|
926
|
+
if not schedule_expression:
|
|
927
|
+
return False
|
|
928
|
+
|
|
929
|
+
# Check for rate expressions (e.g., "rate(1 day)")
|
|
930
|
+
if schedule_expression.startswith('rate('):
|
|
931
|
+
# Extract number and unit
|
|
932
|
+
match = re.match(r'rate\((\d+)\s+(hour|day|week)\)', schedule_expression)
|
|
933
|
+
if match:
|
|
934
|
+
value = int(match.group(1))
|
|
935
|
+
unit = match.group(2)
|
|
936
|
+
|
|
937
|
+
# Convert to hours for comparison
|
|
938
|
+
if unit == 'hour':
|
|
939
|
+
hours = value
|
|
940
|
+
elif unit == 'day':
|
|
941
|
+
hours = value * 24
|
|
942
|
+
elif unit == 'week':
|
|
943
|
+
hours = value * 24 * 7
|
|
944
|
+
|
|
945
|
+
# Must be at least daily (24 hours or less)
|
|
946
|
+
return hours <= 24
|
|
947
|
+
|
|
948
|
+
# Check for cron expressions (e.g., "cron(0 0 * * ? *)")
|
|
949
|
+
elif schedule_expression.startswith('cron('):
|
|
950
|
+
# Daily or more frequent cron patterns
|
|
951
|
+
# This is a simplified check - full cron parsing would be more complex
|
|
952
|
+
return True # Assume cron expressions are configured appropriately
|
|
953
|
+
|
|
954
|
+
return False
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
### Backup Vault Access Policy Check
|
|
958
|
+
|
|
959
|
+
Evaluates backup vault access policies to ensure they don't allow overly permissive access:
|
|
960
|
+
|
|
961
|
+
```python
|
|
962
|
+
def evaluate_backup_vault_policy(self, resource, aws_factory):
|
|
963
|
+
"""Evaluate backup vault access policy for security."""
|
|
964
|
+
vault_name = resource['BackupVaultName']
|
|
965
|
+
vault_arn = resource['BackupVaultArn']
|
|
966
|
+
policy = resource.get('Policy')
|
|
967
|
+
region = resource['Region']
|
|
968
|
+
|
|
969
|
+
# If no policy, vault is secure by default
|
|
970
|
+
if not policy:
|
|
971
|
+
return ComplianceResult(
|
|
972
|
+
resource_id=vault_arn,
|
|
973
|
+
resource_type="AWS::Backup::BackupVault",
|
|
974
|
+
compliance_status="COMPLIANT",
|
|
975
|
+
evaluation_reason="Backup vault has no access policy (secure by default)",
|
|
976
|
+
config_rule_name="backup-vault-access-policy-check",
|
|
977
|
+
region=region,
|
|
978
|
+
timestamp=datetime.now()
|
|
979
|
+
)
|
|
980
|
+
|
|
981
|
+
try:
|
|
982
|
+
# Parse policy JSON
|
|
983
|
+
policy_doc = json.loads(policy) if isinstance(policy, str) else policy
|
|
984
|
+
|
|
985
|
+
# Check for overly permissive principals
|
|
986
|
+
security_issues = []
|
|
987
|
+
|
|
988
|
+
for statement in policy_doc.get('Statement', []):
|
|
989
|
+
principal = statement.get('Principal', {})
|
|
990
|
+
effect = statement.get('Effect', '')
|
|
991
|
+
|
|
992
|
+
# Check for wildcard principals with Allow effect
|
|
993
|
+
if effect == 'Allow':
|
|
994
|
+
if principal == '*' or principal == {'AWS': '*'}:
|
|
995
|
+
security_issues.append("Policy allows access from any principal (*)")
|
|
996
|
+
|
|
997
|
+
# Check for overly broad actions
|
|
998
|
+
actions = statement.get('Action', [])
|
|
999
|
+
if isinstance(actions, str):
|
|
1000
|
+
actions = [actions]
|
|
1001
|
+
|
|
1002
|
+
if 'backup:*' in actions or '*' in actions:
|
|
1003
|
+
security_issues.append("Policy allows all backup actions (*)")
|
|
1004
|
+
|
|
1005
|
+
if security_issues:
|
|
1006
|
+
return ComplianceResult(
|
|
1007
|
+
resource_id=vault_arn,
|
|
1008
|
+
resource_type="AWS::Backup::BackupVault",
|
|
1009
|
+
compliance_status="NON_COMPLIANT",
|
|
1010
|
+
evaluation_reason=f"Backup vault policy has security issues: {'; '.join(security_issues)}",
|
|
1011
|
+
config_rule_name="backup-vault-access-policy-check",
|
|
1012
|
+
region=region,
|
|
1013
|
+
timestamp=datetime.now(),
|
|
1014
|
+
remediation_guidance="Update vault policy to restrict access to specific principals and actions"
|
|
1015
|
+
)
|
|
1016
|
+
|
|
1017
|
+
return ComplianceResult(
|
|
1018
|
+
resource_id=vault_arn,
|
|
1019
|
+
resource_type="AWS::Backup::BackupVault",
|
|
1020
|
+
compliance_status="COMPLIANT",
|
|
1021
|
+
evaluation_reason="Backup vault policy follows security best practices",
|
|
1022
|
+
config_rule_name="backup-vault-access-policy-check",
|
|
1023
|
+
region=region,
|
|
1024
|
+
timestamp=datetime.now()
|
|
1025
|
+
)
|
|
1026
|
+
|
|
1027
|
+
except (json.JSONDecodeError, KeyError) as e:
|
|
1028
|
+
return ComplianceResult(
|
|
1029
|
+
resource_id=vault_arn,
|
|
1030
|
+
resource_type="AWS::Backup::BackupVault",
|
|
1031
|
+
compliance_status="ERROR",
|
|
1032
|
+
evaluation_reason=f"Failed to parse vault policy: {str(e)}",
|
|
1033
|
+
config_rule_name="backup-vault-access-policy-check",
|
|
1034
|
+
region=region,
|
|
1035
|
+
timestamp=datetime.now(),
|
|
1036
|
+
remediation_guidance="Verify vault policy is valid JSON"
|
|
1037
|
+
)
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
### Backup Controls Integration
|
|
1041
|
+
|
|
1042
|
+
The AWS Backup service-level controls complement the existing resource-specific backup controls:
|
|
1043
|
+
|
|
1044
|
+
**Resource-Specific Controls** (existing):
|
|
1045
|
+
- `backup-recovery-point-encrypted`: Validates individual recovery points are encrypted
|
|
1046
|
+
- `backup-recovery-point-minimum-retention-check`: Checks retention of recovery points
|
|
1047
|
+
- `backup-recovery-point-manual-deletion-disabled`: Ensures manual deletion is disabled
|
|
1048
|
+
- And 9 other resource-specific backup controls
|
|
1049
|
+
|
|
1050
|
+
**Service-Level Controls** (new):
|
|
1051
|
+
- `backup-plan-min-frequency-and-min-retention-check`: Validates backup plan policies
|
|
1052
|
+
- `backup-vault-access-policy-check`: Checks backup vault security
|
|
1053
|
+
|
|
1054
|
+
This hybrid approach provides comprehensive backup coverage at both the service configuration level and individual resource level.
|
docs/cli-reference.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CLI Reference
|
|
2
2
|
|
|
3
|
-
Complete command-line interface reference for the AWS CIS Controls Compliance Assessment Framework - a production-ready enterprise solution with
|
|
3
|
+
Complete command-line interface reference for the AWS CIS Controls Compliance Assessment Framework - a production-ready enterprise solution with 149 implemented rules (133 CIS Controls + 9 bonus security enhancements + 7 audit logging controls).
|
|
4
4
|
|
|
5
5
|
## Table of Contents
|
|
6
6
|
|