Skip to content

Commit d18c8fe

Browse files
committed
feat(CKV_AWS_341): ensure IAM role max session duration does not exceed 1 hour
1 parent 852def3 commit d18c8fe

2 files changed

Lines changed: 118 additions & 0 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from checkov.common.models.enums import CheckCategories, CheckResult
2+
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
3+
4+
MAX_SESSION_DURATION = 3600 # 1 hour in seconds
5+
6+
7+
class IAMRoleMaxSessionDuration(BaseResourceCheck):
8+
def __init__(self):
9+
name = "Ensure IAM role max session duration does not exceed 1 hour"
10+
id = "CKV_AWS_341"
11+
supported_resources = ["aws_iam_role"]
12+
categories = [CheckCategories.IAM]
13+
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)
14+
15+
def scan_resource_conf(self, conf):
16+
"""
17+
Looks for max_session_duration in aws_iam_role resources.
18+
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role
19+
20+
The default value in AWS is 3600 seconds (1 hour).
21+
Allowing sessions longer than 1 hour increases the blast radius
22+
of a compromised credential.
23+
24+
Pass: max_session_duration is not set (defaults to 3600) or is <= 3600
25+
Fail: max_session_duration is set to a value > 3600
26+
"""
27+
max_session_duration = conf.get("max_session_duration")
28+
29+
# not set — defaults to 3600, passes
30+
if not max_session_duration:
31+
return CheckResult.PASSED
32+
33+
# handle list wrapping from Terraform parser
34+
if isinstance(max_session_duration, list):
35+
max_session_duration = max_session_duration[0]
36+
37+
# skip if variable reference (can't evaluate at scan time)
38+
if not isinstance(max_session_duration, int):
39+
return CheckResult.UNKNOWN
40+
41+
if max_session_duration <= MAX_SESSION_DURATION:
42+
return CheckResult.PASSED
43+
44+
return CheckResult.FAILED
45+
46+
47+
scanner = IAMRoleMaxSessionDuration()
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import unittest
2+
from pathlib import Path
3+
4+
from checkov.terraform.checks.resource.aws.IAMRoleMaxSessionDuration import scanner
5+
from checkov.common.models.enums import CheckResult
6+
7+
8+
class TestIAMRoleMaxSessionDuration(unittest.TestCase):
9+
10+
def test_success_no_max_session_duration(self):
11+
"""Role with no max_session_duration set — defaults to 3600, should pass."""
12+
resource_conf = {
13+
"name": ["test_role"],
14+
"assume_role_policy": ['{"Version":"2012-10-17"}'],
15+
}
16+
result = scanner.scan_resource_conf(conf=resource_conf)
17+
self.assertEqual(result, CheckResult.PASSED)
18+
19+
def test_success_max_session_duration_3600(self):
20+
"""Role with max_session_duration exactly 3600 — should pass."""
21+
resource_conf = {
22+
"name": ["test_role"],
23+
"assume_role_policy": ['{"Version":"2012-10-17"}'],
24+
"max_session_duration": [3600],
25+
}
26+
result = scanner.scan_resource_conf(conf=resource_conf)
27+
self.assertEqual(result, CheckResult.PASSED)
28+
29+
def test_success_max_session_duration_1800(self):
30+
"""Role with max_session_duration below 3600 — should pass."""
31+
resource_conf = {
32+
"name": ["test_role"],
33+
"assume_role_policy": ['{"Version":"2012-10-17"}'],
34+
"max_session_duration": [1800],
35+
}
36+
result = scanner.scan_resource_conf(conf=resource_conf)
37+
self.assertEqual(result, CheckResult.PASSED)
38+
39+
def test_failure_max_session_duration_7200(self):
40+
"""Role with max_session_duration of 7200 (2 hours) — should fail."""
41+
resource_conf = {
42+
"name": ["test_role"],
43+
"assume_role_policy": ['{"Version":"2012-10-17"}'],
44+
"max_session_duration": [7200],
45+
}
46+
result = scanner.scan_resource_conf(conf=resource_conf)
47+
self.assertEqual(result, CheckResult.FAILED)
48+
49+
def test_failure_max_session_duration_43200(self):
50+
"""Role with max_session_duration of 43200 (12 hours, AWS max) — should fail."""
51+
resource_conf = {
52+
"name": ["test_role"],
53+
"assume_role_policy": ['{"Version":"2012-10-17"}'],
54+
"max_session_duration": [43200],
55+
}
56+
result = scanner.scan_resource_conf(conf=resource_conf)
57+
self.assertEqual(result, CheckResult.FAILED)
58+
59+
def test_unknown_variable_reference(self):
60+
"""Role with max_session_duration as a variable reference — should be UNKNOWN."""
61+
resource_conf = {
62+
"name": ["test_role"],
63+
"assume_role_policy": ['{"Version":"2012-10-17"}'],
64+
"max_session_duration": ["${var.max_session_duration}"],
65+
}
66+
result = scanner.scan_resource_conf(conf=resource_conf)
67+
self.assertEqual(result, CheckResult.UNKNOWN)
68+
69+
70+
if __name__ == "__main__":
71+
unittest.main()

0 commit comments

Comments
 (0)