feat(iam_checks): add several checks for iam (#1264)

* feat(extra71): add iam_administrator_access_with_mfa check.

* feat(checks): add extra7125 and extra7123

* feat(checks): add check14

* feat(checks): add check112

* feat(checks): add check11

* feat(checks): add check114 and check113

* feat(checks): add check12

* feat(classes): add IAM classess.

* Update iam_root_hardware_mfa_enabled.py

* fix(comments): Resolve comments.

Co-authored-by: sergargar <sergio@verica.io>
This commit is contained in:
Sergio Garcia
2022-07-22 12:14:49 +02:00
committed by GitHub
parent 7d0a95e98f
commit ed1572d2d9
35 changed files with 1077 additions and 186 deletions

View File

@@ -20,4 +20,4 @@ pytest = "7.1.2"
[dev-packages]
[requires]
python_version = "3.9"
python_version = "3"

174
Pipfile.lock generated
View File

@@ -1,11 +1,11 @@
{
"_meta": {
"hash": {
"sha256": "e77c8b5d556b7e3c336616485fe5c853f203896df85be049b89a4618bef8fab7"
"sha256": "c5d684bfa255c02f7676641165c651ebb46c7f4cab5c3d2916da4a7d4bd0f0ce"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.9"
"python_version": "3"
},
"sources": [
{
@@ -42,19 +42,19 @@
},
"boto3": {
"hashes": [
"sha256:67d404c643091d4aa37fc485193289ad859f1f65f94d0fa544e13bdd1d4187c1",
"sha256:c9a9f893561f64f5b81de197714ac4951251a328672a8dba28ad4c4a589c3adf"
"sha256:5c775dcb12ca5d6be3f5aa3c49d77783faa64eb30fd3f4af93ff116bb42f9ffb",
"sha256:5d9bcc355cf6edd7f3849fedac4252e12a0aa2b436cdbc0d4371b16a0f852a30"
],
"index": "pypi",
"version": "==1.24.22"
"version": "==1.24.34"
},
"botocore": {
"hashes": [
"sha256:7145d9b7cae87999a9f074de700d02a1b3222ee7d1863aa631ff56c5fc868035",
"sha256:f57cb33446deef92e552b0be0e430d475c73cf64bc9e46cdb4783cdfe39cb6bb"
"sha256:0d824a5315f5f5c3bea53c14107a69695ef43190edf647f1281bac8f172ca77c",
"sha256:9c695d47f1f1212f3e306e51f7bacdf67e58055194ddcf7d8296660b124cf135"
],
"index": "pypi",
"version": "==1.27.22"
"version": "==1.27.34"
},
"certifi": {
"hashes": [
@@ -159,78 +159,78 @@
},
"coverage": {
"hashes": [
"sha256:01c5615d13f3dd3aa8543afc069e5319cfa0c7d712f6e04b920431e5c564a749",
"sha256:106c16dfe494de3193ec55cac9640dd039b66e196e4641fa8ac396181578b982",
"sha256:129cd05ba6f0d08a766d942a9ed4b29283aff7b2cccf5b7ce279d50796860bb3",
"sha256:145f296d00441ca703a659e8f3eb48ae39fb083baba2d7ce4482fb2723e050d9",
"sha256:1480ff858b4113db2718848d7b2d1b75bc79895a9c22e76a221b9d8d62496428",
"sha256:269eaa2c20a13a5bf17558d4dc91a8d078c4fa1872f25303dddcbba3a813085e",
"sha256:26dff09fb0d82693ba9e6231248641d60ba606150d02ed45110f9ec26404ed1c",
"sha256:2bd9a6fc18aab8d2e18f89b7ff91c0f34ff4d5e0ba0b33e989b3cd4194c81fd9",
"sha256:309ce4a522ed5fca432af4ebe0f32b21d6d7ccbb0f5fcc99290e71feba67c264",
"sha256:3384f2a3652cef289e38100f2d037956194a837221edd520a7ee5b42d00cc605",
"sha256:342d4aefd1c3e7f620a13f4fe563154d808b69cccef415415aece4c786665397",
"sha256:39ee53946bf009788108b4dd2894bf1349b4e0ca18c2016ffa7d26ce46b8f10d",
"sha256:4321f075095a096e70aff1d002030ee612b65a205a0a0f5b815280d5dc58100c",
"sha256:4803e7ccf93230accb928f3a68f00ffa80a88213af98ed338a57ad021ef06815",
"sha256:4ce1b258493cbf8aec43e9b50d89982346b98e9ffdfaae8ae5793bc112fb0068",
"sha256:664a47ce62fe4bef9e2d2c430306e1428ecea207ffd68649e3b942fa8ea83b0b",
"sha256:75ab269400706fab15981fd4bd5080c56bd5cc07c3bccb86aab5e1d5a88dc8f4",
"sha256:83c4e737f60c6936460c5be330d296dd5b48b3963f48634c53b3f7deb0f34ec4",
"sha256:84631e81dd053e8a0d4967cedab6db94345f1c36107c71698f746cb2636c63e3",
"sha256:84e65ef149028516c6d64461b95a8dbcfce95cfd5b9eb634320596173332ea84",
"sha256:865d69ae811a392f4d06bde506d531f6a28a00af36f5c8649684a9e5e4a85c83",
"sha256:87f4f3df85aa39da00fd3ec4b5abeb7407e82b68c7c5ad181308b0e2526da5d4",
"sha256:8c08da0bd238f2970230c2a0d28ff0e99961598cb2e810245d7fc5afcf1254e8",
"sha256:961e2fb0680b4f5ad63234e0bf55dfb90d302740ae9c7ed0120677a94a1590cb",
"sha256:9b3e07152b4563722be523e8cd0b209e0d1a373022cfbde395ebb6575bf6790d",
"sha256:a7f3049243783df2e6cc6deafc49ea123522b59f464831476d3d1448e30d72df",
"sha256:bf5601c33213d3cb19d17a796f8a14a9eaa5e87629a53979a5981e3e3ae166f6",
"sha256:cec3a0f75c8f1031825e19cd86ee787e87cf03e4fd2865c79c057092e69e3a3b",
"sha256:d42c549a8f41dc103a8004b9f0c433e2086add8a719da00e246e17cbe4056f72",
"sha256:d67d44996140af8b84284e5e7d398e589574b376fb4de8ccd28d82ad8e3bea13",
"sha256:d9c80df769f5ec05ad21ea34be7458d1dc51ff1fb4b2219e77fe24edf462d6df",
"sha256:e57816f8ffe46b1df8f12e1b348f06d164fd5219beba7d9433ba79608ef011cc",
"sha256:ee2ddcac99b2d2aec413e36d7a429ae9ebcadf912946b13ffa88e7d4c9b712d6",
"sha256:f02cbbf8119db68455b9d763f2f8737bb7db7e43720afa07d8eb1604e5c5ae28",
"sha256:f1d5aa2703e1dab4ae6cf416eb0095304f49d004c39e9db1d86f57924f43006b",
"sha256:f5b66caa62922531059bc5ac04f836860412f7f88d38a476eda0a6f11d4724f4",
"sha256:f69718750eaae75efe506406c490d6fc5a6161d047206cc63ce25527e8a3adad",
"sha256:fb73e0011b8793c053bfa85e53129ba5f0250fdc0392c1591fd35d915ec75c46",
"sha256:fd180ed867e289964404051a958f7cccabdeed423f91a899829264bb7974d3d3",
"sha256:fdb6f7bd51c2d1714cea40718f6149ad9be6a2ee7d93b19e9f00934c0f2a74d9",
"sha256:ffa9297c3a453fba4717d06df579af42ab9a28022444cae7fa605af4df612d54"
"sha256:0895ea6e6f7f9939166cc835df8fa4599e2d9b759b02d1521b574e13b859ac32",
"sha256:0f211df2cba951ffcae210ee00e54921ab42e2b64e0bf2c0befc977377fb09b7",
"sha256:147605e1702d996279bb3cc3b164f408698850011210d133a2cb96a73a2f7996",
"sha256:24b04d305ea172ccb21bee5bacd559383cba2c6fcdef85b7701cf2de4188aa55",
"sha256:25b7ec944f114f70803d6529394b64f8749e93cbfac0fe6c5ea1b7e6c14e8a46",
"sha256:2b20286c2b726f94e766e86a3fddb7b7e37af5d0c635bdfa7e4399bc523563de",
"sha256:2dff52b3e7f76ada36f82124703f4953186d9029d00d6287f17c68a75e2e6039",
"sha256:2f8553878a24b00d5ab04b7a92a2af50409247ca5c4b7a2bf4eabe94ed20d3ee",
"sha256:3def6791adf580d66f025223078dc84c64696a26f174131059ce8e91452584e1",
"sha256:422fa44070b42fef9fb8dabd5af03861708cdd6deb69463adc2130b7bf81332f",
"sha256:4f89d8e03c8a3757aae65570d14033e8edf192ee9298303db15955cadcff0c63",
"sha256:5336e0352c0b12c7e72727d50ff02557005f79a0b8dcad9219c7c4940a930083",
"sha256:54d8d0e073a7f238f0666d3c7c0d37469b2aa43311e4024c925ee14f5d5a1cbe",
"sha256:5ef42e1db047ca42827a85e34abe973971c635f83aed49611b7f3ab49d0130f0",
"sha256:5f65e5d3ff2d895dab76b1faca4586b970a99b5d4b24e9aafffc0ce94a6022d6",
"sha256:6c3ccfe89c36f3e5b9837b9ee507472310164f352c9fe332120b764c9d60adbe",
"sha256:6d0b48aff8e9720bdec315d67723f0babd936a7211dc5df453ddf76f89c59933",
"sha256:6fe75dcfcb889b6800f072f2af5a331342d63d0c1b3d2bf0f7b4f6c353e8c9c0",
"sha256:79419370d6a637cb18553ecb25228893966bd7935a9120fa454e7076f13b627c",
"sha256:7bb00521ab4f99fdce2d5c05a91bddc0280f0afaee0e0a00425e28e209d4af07",
"sha256:80db4a47a199c4563d4a25919ff29c97c87569130375beca3483b41ad5f698e8",
"sha256:866ebf42b4c5dbafd64455b0a1cd5aa7b4837a894809413b930026c91e18090b",
"sha256:8af6c26ba8df6338e57bedbf916d76bdae6308e57fc8f14397f03b5da8622b4e",
"sha256:a13772c19619118903d65a91f1d5fea84be494d12fd406d06c849b00d31bf120",
"sha256:a697977157adc052284a7160569b36a8bbec09db3c3220642e6323b47cec090f",
"sha256:a9032f9b7d38bdf882ac9f66ebde3afb8145f0d4c24b2e600bc4c6304aafb87e",
"sha256:b5e28db9199dd3833cc8a07fa6cf429a01227b5d429facb56eccd765050c26cd",
"sha256:c77943ef768276b61c96a3eb854eba55633c7a3fddf0a79f82805f232326d33f",
"sha256:d230d333b0be8042ac34808ad722eabba30036232e7a6fb3e317c49f61c93386",
"sha256:d4548be38a1c810d79e097a38107b6bf2ff42151900e47d49635be69943763d8",
"sha256:d4e7ced84a11c10160c0697a6cc0b214a5d7ab21dfec1cd46e89fbf77cc66fae",
"sha256:d56f105592188ce7a797b2bd94b4a8cb2e36d5d9b0d8a1d2060ff2a71e6b9bbc",
"sha256:d714af0bdba67739598849c9f18efdcc5a0412f4993914a0ec5ce0f1e864d783",
"sha256:d774d9e97007b018a651eadc1b3970ed20237395527e22cbeb743d8e73e0563d",
"sha256:e0524adb49c716ca763dbc1d27bedce36b14f33e6b8af6dba56886476b42957c",
"sha256:e2618cb2cf5a7cc8d698306e42ebcacd02fb7ef8cfc18485c59394152c70be97",
"sha256:e36750fbbc422c1c46c9d13b937ab437138b998fe74a635ec88989afb57a3978",
"sha256:edfdabe7aa4f97ed2b9dd5dde52d2bb29cb466993bb9d612ddd10d0085a683cf",
"sha256:f22325010d8824594820d6ce84fa830838f581a7fd86a9235f0d2ed6deb61e29",
"sha256:f23876b018dfa5d3e98e96f5644b109090f16a4acb22064e0f06933663005d39",
"sha256:f7bd0ffbcd03dc39490a1f40b2669cc414fae0c4e16b77bb26806a4d0b7d1452"
],
"index": "pypi",
"version": "==6.4.1"
"version": "==6.4.2"
},
"cryptography": {
"hashes": [
"sha256:093cb351031656d3ee2f4fa1be579a8c69c754cf874206be1d4cf3b542042804",
"sha256:0cc20f655157d4cfc7bada909dc5cc228211b075ba8407c46467f63597c78178",
"sha256:1b9362d34363f2c71b7853f6251219298124aa4cc2075ae2932e64c91a3e2717",
"sha256:1f3bfbd611db5cb58ca82f3deb35e83af34bb8cf06043fa61500157d50a70982",
"sha256:2bd1096476aaac820426239ab534b636c77d71af66c547b9ddcd76eb9c79e004",
"sha256:31fe38d14d2e5f787e0aecef831457da6cec68e0bb09a35835b0b44ae8b988fe",
"sha256:3b8398b3d0efc420e777c40c16764d6870bcef2eb383df9c6dbb9ffe12c64452",
"sha256:3c81599befb4d4f3d7648ed3217e00d21a9341a9a688ecdd615ff72ffbed7336",
"sha256:419c57d7b63f5ec38b1199a9521d77d7d1754eb97827bbb773162073ccd8c8d4",
"sha256:46f4c544f6557a2fefa7ac8ac7d1b17bf9b647bd20b16decc8fbcab7117fbc15",
"sha256:471e0d70201c069f74c837983189949aa0d24bb2d751b57e26e3761f2f782b8d",
"sha256:59b281eab51e1b6b6afa525af2bd93c16d49358404f814fe2c2410058623928c",
"sha256:731c8abd27693323b348518ed0e0705713a36d79fdbd969ad968fbef0979a7e0",
"sha256:95e590dd70642eb2079d280420a888190aa040ad20f19ec8c6e097e38aa29e06",
"sha256:a68254dd88021f24a68b613d8c51d5c5e74d735878b9e32cc0adf19d1f10aaf9",
"sha256:a7d5137e556cc0ea418dca6186deabe9129cee318618eb1ffecbd35bee55ddc1",
"sha256:aeaba7b5e756ea52c8861c133c596afe93dd716cbcacae23b80bc238202dc023",
"sha256:dc26bb134452081859aa21d4990474ddb7e863aa39e60d1592800a8865a702de",
"sha256:e53258e69874a306fcecb88b7534d61820db8a98655662a3dd2ec7f1afd9132f",
"sha256:ef15c2df7656763b4ff20a9bc4381d8352e6640cfeb95c2972c38ef508e75181",
"sha256:f224ad253cc9cea7568f49077007d2263efa57396a2f2f78114066fd54b5c68e",
"sha256:f8ec91983e638a9bcd75b39f1396e5c0dc2330cbd9ce4accefe68717e6779e0a"
"sha256:190f82f3e87033821828f60787cfa42bff98404483577b591429ed99bed39d59",
"sha256:2be53f9f5505673eeda5f2736bea736c40f051a739bfae2f92d18aed1eb54596",
"sha256:30788e070800fec9bbcf9faa71ea6d8068f5136f60029759fd8c3efec3c9dcb3",
"sha256:3d41b965b3380f10e4611dbae366f6dc3cefc7c9ac4e8842a806b9672ae9add5",
"sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab",
"sha256:549153378611c0cca1042f20fd9c5030d37a72f634c9326e225c9f666d472884",
"sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82",
"sha256:6bc95ed67b6741b2607298f9ea4932ff157e570ef456ef7ff0ef4884a134cc4b",
"sha256:7099a8d55cd49b737ffc99c17de504f2257e3787e02abe6d1a6d136574873441",
"sha256:75976c217f10d48a8b5a8de3d70c454c249e4b91851f6838a4e48b8f41eb71aa",
"sha256:7bc997818309f56c0038a33b8da5c0bfbb3f1f067f315f9abd6fc07ad359398d",
"sha256:80f49023dd13ba35f7c34072fa17f604d2f19bf0989f292cedf7ab5770b87a0b",
"sha256:91ce48d35f4e3d3f1d83e29ef4a9267246e6a3be51864a5b7d2247d5086fa99a",
"sha256:a958c52505c8adf0d3822703078580d2c0456dd1d27fabfb6f76fe63d2971cd6",
"sha256:b62439d7cd1222f3da897e9a9fe53bbf5c104fff4d60893ad1355d4c14a24157",
"sha256:b7f8dd0d4c1f21759695c05a5ec8536c12f31611541f8904083f3dc582604280",
"sha256:d204833f3c8a33bbe11eda63a54b1aad7aa7456ed769a982f21ec599ba5fa282",
"sha256:e007f052ed10cc316df59bc90fbb7ff7950d7e2919c9757fd42a2b8ecf8a5f67",
"sha256:f2dcb0b3b63afb6df7fd94ec6fbddac81b5492513f7b0436210d390c14d46ee8",
"sha256:f721d1885ecae9078c3f6bbe8a88bc0786b6e749bf32ccec1ef2b18929a05046",
"sha256:f7a6de3e98771e183645181b3627e2563dcde3ce94a9e42a3f427d2255190327",
"sha256:f8c0a6e9e1dd3eb0414ba320f85da6b0dcbd543126e30fcc546e7372a7fbf3b9"
],
"markers": "python_version >= '3.6'",
"version": "==37.0.2"
"version": "==37.0.4"
},
"dparse": {
"hashes": [
@@ -567,19 +567,19 @@
},
"safety": {
"hashes": [
"sha256:77cebdd128ce47b941e68a1b3bbc29fbbd2b9e98d11f179c5def64c1d05da295",
"sha256:d739d00a9e4203cfaba34540c822a73ca1d327159ed7776b3dce09391f81c35d"
"sha256:05ba551fb61ef24c864835d21089f75bc8b37292680047b9f29693a6552e2fc7",
"sha256:dbc5dffa2e47da76cc43dfe8cbbbfca99d29118d0c6c54dfcfa11c2bd349dff6"
],
"index": "pypi",
"version": "==2.0.0"
"version": "==2.1.1"
},
"setuptools": {
"hashes": [
"sha256:16923d366ced322712c71ccb97164d07472abeecd13f3a6c283f6d5d26722793",
"sha256:db3b8e2f922b2a910a29804776c643ea609badb6a32c4bcc226fd4fd902cce65"
"sha256:0d33c374d41c7863419fc8f6c10bfe25b7b498aa34164d135c622e52580c6b16",
"sha256:c04b44a57a6265fe34a4a444e965884716d34bae963119a76353434d6f18e450"
],
"markers": "python_version >= '3.7'",
"version": "==63.1.0"
"version": "==63.2.0"
},
"six": {
"hashes": [
@@ -599,11 +599,11 @@
},
"stevedore": {
"hashes": [
"sha256:a547de73308fd7e90075bb4d301405bebf705292fa90a90fc3bcf9133f58616c",
"sha256:f40253887d8712eaa2bb0ea3830374416736dc8ec0e22f5a65092c1174c44335"
"sha256:87e4d27fe96d0d7e4fc24f0cbe3463baae4ec51e81d95fbe60d2474636e0c7d8",
"sha256:f82cc99a1ff552310d19c379827c2c64dd9f85a38bcd5559db2470161867b786"
],
"markers": "python_version >= '3.6'",
"version": "==3.5.0"
"markers": "python_version >= '3.8'",
"version": "==4.0.0"
},
"sure": {
"hashes": [
@@ -638,11 +638,11 @@
},
"urllib3": {
"hashes": [
"sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
"sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
"sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec",
"sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==1.26.9"
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'",
"version": "==1.26.10"
},
"vulture": {
"hashes": [

View File

@@ -189,13 +189,10 @@ class Check_Output_CSV:
report.check_metadata.Remediation.Code.Terraform
)
self.remediation_recommendation_code_cli = (
report.check_metadata.Remediation.Code.cli
)
self.remediation_recommendation_code_cli = (
report.check_metadata.Remediation.Code.cli
report.check_metadata.Remediation.Code.CLI
)
self.remediation_recommendation_code_other = (
report.check_metadata.Remediation.Code.other
report.check_metadata.Remediation.Code.Other
)
self.categories = self.__unroll_list__(report.check_metadata.Categories)
self.depends_on = self.__unroll_list__(report.check_metadata.DependsOn)

View File

@@ -0,0 +1,37 @@
{
"Categories": [],
"CheckAlias": "extra71",
"CheckID": "iam_administrator_access_with_mfa",
"CheckName": "iam_administrator_access_with_mfa",
"CheckTitle": "Ensure users of groups with AdministratorAccess policy have MFA tokens enabled",
"CheckType": "Infrastructure Security",
"Compliance": [],
"DependsOn": [],
"Description": "Ensure users of groups with AdministratorAccess policy have MFA tokens enabled",
"Notes": "",
"Provider": "aws",
"RelatedTo": [],
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Ensure this repository and its contents should be publicly accessible.",
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html"
}
},
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"ResourceType": "AwsIamUser",
"Risk": "Policy may allow Anonymous users to perform actions.",
"ServiceName": "iam",
"Severity": "high",
"SubServiceName": "",
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
}
}

View File

@@ -0,0 +1,64 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.iam.iam_service import iam_client
class iam_administrator_access_with_mfa(Check):
def execute(self) -> Check_Report:
findings = []
response = iam_client.groups
if response:
for group in response:
report = Check_Report(self.metadata)
report.resource_id = group.name
report.resource_arn = group.arn
report.region = "us-east-1"
if group.attached_policies:
admin_policy = False
for group_policy in group.attached_policies:
if (
group_policy["PolicyArn"]
== "arn:aws:iam::aws:policy/AdministratorAccess"
):
admin_policy = True
# users in group are Administrators
if group.users:
for group_user in group.users:
for user in iam_client.credential_report:
if (
user["user"] == group_user.name
and user["mfa_active"] == "false"
):
report.status = "FAIL"
report.status_extended = f"Group {group.name} provides administrator access to User {group_user.name} with MFA disabled."
findings.append(report)
elif (
user["user"] == group_user.name
and user["mfa_active"] == "true"
):
report.status = "PASS"
report.status_extended = f"Group {group.name} provides administrator access to User {group_user.name} with MFA enabled."
findings.append(report)
else:
report.status = "PASS"
report.status_extended = f"Group {group.name} provides administrative access but does not have users."
findings.append(report)
if not admin_policy:
report.status = "PASS"
report.status_extended = (
f"Group {group.name} provides non-administrative access."
)
findings.append(report)
else:
report.status = "PASS"
report.status_extended = f"Group {group.name} has no policies."
findings.append(report)
else:
report = Check_Report(self.metadata)
report.status = "PASS"
report.status_extended = "There is no IAM groups."
report.region = iam_client.region
findings.append(report)
return findings

View File

@@ -0,0 +1,48 @@
{
"Categories": [],
"CheckAlias": "check11",
"CheckID": "iam_avoid_root_usage",
"CheckName": "iam_avoid_root_usage",
"CheckTitle": "Avoid the use of the root accounts",
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
"Compliance": [
{
"Control": [
"1.1"
],
"Framework": "CIS-AWS",
"Group": [
"level1"
],
"Version": "1.4"
}
],
"DependsOn": [],
"Description": "Avoid the use of the root account",
"Notes": "",
"Provider": "aws",
"RelatedTo": [],
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Follow the remediation instructions of the Ensure IAM policies are attached only to groups or roles recommendation.",
"Url": "http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html"
}
},
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"ResourceType": "AwsIamUser",
"Risk": "The root account has unrestricted access to all resources in the AWS account. It is highly recommended that the use of this account be avoided.",
"ServiceName": "iam",
"Severity": "high",
"SubServiceName": "",
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
}
}

View File

@@ -0,0 +1,61 @@
import datetime
from lib.check.models import Check, Check_Report
from providers.aws.services.iam.iam_service import iam_client
maximum_access_days = 1
class iam_avoid_root_usage(Check):
def execute(self) -> Check_Report:
findings = []
response = iam_client.credential_report
if response:
for user in response:
if user["user"] == "<root_account>":
report = Check_Report(self.metadata)
report.region = "us-east-1"
report.resource_id = user["user"]
report.resource_arn = user["arn"]
if (
user["password_last_used"] != "no_information"
or user["access_key_1_last_used_date"] != "N/A"
or user["access_key_2_last_used_date"] != "N/A"
):
if user["password_last_used"] != "no_information":
days_since_accessed = (
datetime.datetime.now()
- datetime.datetime.strptime(
user["password_last_used"],
"%Y-%m-%dT%H:%M:%S+00:00",
)
).days
elif user["access_key_1_last_used_date"] != "N/A":
days_since_accessed = (
datetime.datetime.now()
- datetime.datetime.strptime(
user["access_key_1_last_used_date"],
"%Y-%m-%dT%H:%M:%S+00:00",
)
).days
elif user["access_key_2_last_used_date"] != "N/A":
days_since_accessed = (
datetime.datetime.now()
- datetime.datetime.strptime(
user["access_key_2_last_used_date"],
"%Y-%m-%dT%H:%M:%S+00:00",
)
).days
if days_since_accessed > maximum_access_days:
report.status = "FAIL"
report.status_extended = f"Root user in the account was last accessed {days_since_accessed} days ago."
else:
report.status = "PASS"
report.status_extended = f"Root user in the account wasn't accessed in the last {maximum_access_days} days."
else:
report.status = "PASS"
report.status_extended = f"Root user in the account wasn't accessed in the last {maximum_access_days} days."
findings.append(report)
return findings

View File

@@ -1,56 +1,35 @@
{
"Categories": [
"cat1",
"cat2"
],
"Categories": [],
"CheckAlias": "extra774",
"CheckID": "iam_disable_30_days_credentials",
"CheckName": "iam_disable_30_days_credentials",
"CheckTitle": "Ensure credentials unused for 30 days or greater are disabled",
"CheckType": "Software and Configuration Checks",
"Compliance": [
{
"Control": [
"4.4"
],
"Framework": "CIS-AWS",
"Group": [
"level1",
"level2"
],
"Version": "1.4"
}
],
"DependsOn": [
"othercheck1",
"othercheck2"
],
"Compliance": [],
"DependsOn": [],
"Description": "Ensure credentials unused for 30 days or greater are disabled",
"Notes": "additional information",
"Notes": "",
"Provider": "aws",
"RelatedTo": [
"othercheck3",
"othercheck4"
],
"RelatedUrl": "https://serviceofficialsiteorpageforthissubject",
"RelatedTo": [],
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "cli command or URL to the cli command location.",
"NativeIaC": "code or URL to the code location.",
"Other": "cli command or URL to the cli command location.",
"Terraform": "code or URL to the code location."
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Run sudo yum update and cross your fingers and toes.",
"Url": "https://myfp.com/recommendations/dangerous_things_and_how_to_fix_them.html"
"Text": "Find the credentials that they were using and ensure that they are no longer operational. Ideally; you delete credentials if they are no longer needed. You can always recreate them at a later date if the need arises. At the very least; you should change the password or deactivate the access keys so that the former users no longer have access.",
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_finding-unused.html"
}
},
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"ResourceType": "AwsIamAccessAnalyzer",
"Risk": "Risk associated.",
"ResourceType": "AwsIamUser",
"Risk": "To increase the security of your AWS account; remove IAM user credentials (that is; passwords and access keys) that are not needed. For example; when users leave your organization or no longer need AWS access.",
"ServiceName": "iam",
"Severity": "low",
"SubServiceName": "accessanalyzer",
"Severity": "medium",
"SubServiceName": "",
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"

View File

@@ -1,4 +1,4 @@
from datetime import datetime
import datetime
from lib.check.models import Check, Check_Report
from providers.aws.services.iam.iam_service import iam_client
@@ -14,34 +14,38 @@ class iam_disable_30_days_credentials(Check):
if response:
for user in response:
report = Check_Report(self.metadata)
report.resource_id = user["UserName"]
report.resource_arn = user["Arn"]
report.resource_id = user.name
report.resource_arn = user.arn
report.region = "us-east-1"
if "PasswordLastUsed" in user and user["PasswordLastUsed"] != "":
if user.password_last_used and user.password_last_used != "":
try:
time_since_insertion = (
datetime.datetime.now(datetime.timezone.utc)
- user["PasswordLastUsed"]
datetime.datetime.now()
- datetime.datetime.strptime(
user.password_last_used, "%Y-%m-%dT%H:%M:%S+00:00"
)
)
if time_since_insertion.days > maximum_expiration_days:
report.status = "FAIL"
report.status_extended = f"User {user['UserName']} has not logged into the console in the past 30 days"
report.status_extended = f"User {user.name} has not logged into the console in the past 30 days."
else:
report.status = "PASS"
report.status_extended = f"User {user['UserName']} has logged into the console in the past 30 days"
report.status_extended = f"User {user.name} has logged into the console in the past 30 days."
except KeyError:
pass
else:
report.status = "PASS"
report.status_extended = f"User {user['UserName']} has not a console password or is unused."
report.status_extended = (
f"User {user.name} has not a console password or is unused."
)
# Append report
findings.append(report)
else:
report = Check_Report(self.metadata)
report.status = "PASS"
report.status_extended = "There is no IAM users"
report.status_extended = "There is no IAM users."
report.region = iam_client.region
findings.append(report)

View File

@@ -1,8 +1,5 @@
{
"Categories": [
"cat1",
"cat2"
],
"Categories": [],
"CheckAlias": "check13",
"CheckID": "iam_disable_90_days_credentials",
"CheckName": "iam_disable_90_days_credentials",
@@ -11,46 +8,39 @@
"Compliance": [
{
"Control": [
"4.4"
"1.3"
],
"Framework": "CIS-AWS",
"Group": [
"level1",
"level2"
"level1"
],
"Version": "1.4"
}
],
"DependsOn": [
"othercheck1",
"othercheck2"
],
"DependsOn": [],
"Description": "Ensure credentials unused for 90 days or greater are disabled",
"Notes": "additional information",
"Notes": "",
"Provider": "aws",
"RelatedTo": [
"othercheck3",
"othercheck4"
],
"RelatedUrl": "https://serviceofficialsiteorpageforthissubject",
"RelatedTo": [],
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "cli command or URL to the cli command location.",
"NativeIaC": "code or URL to the code location.",
"Other": "cli command or URL to the cli command location.",
"Terraform": "code or URL to the code location."
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Run sudo yum update and cross your fingers and toes.",
"Url": "https://myfp.com/recommendations/dangerous_things_and_how_to_fix_them.html"
"Text": "Find the credentials that they were using and ensure that they are no longer operational. Ideally; you delete credentials if they are no longer needed. You can always recreate them at a later date if the need arises. At the very least; you should change the password or deactivate the access keys so that the former users no longer have access.",
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_finding-unused.html"
}
},
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"ResourceType": "AwsIamAccessAnalyzer",
"Risk": "Risk associated.",
"ResourceType": "AwsIamUser",
"Risk": "AWS IAM users can access AWS resources using different types of credentials (passwords or access keys). It is recommended that all credentials that have been unused in 90 or greater days be removed or deactivated.",
"ServiceName": "iam",
"Severity": "low",
"SubServiceName": "accessanalyzer",
"Severity": "medium",
"SubServiceName": "",
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"

View File

@@ -1,4 +1,4 @@
from datetime import datetime
import datetime
from lib.check.models import Check, Check_Report
from providers.aws.services.iam.iam_service import iam_client
@@ -15,33 +15,37 @@ class iam_disable_90_days_credentials(Check):
for user in response:
report = Check_Report(self.metadata)
report.region = "us-east-1"
report.resource_id = user["UserName"]
report.resource_arn = user["Arn"]
if "PasswordLastUsed" in user and user["PasswordLastUsed"] != "":
report.resource_id = user.name
report.resource_arn = user.arn
if user.password_last_used and user.password_last_used != "":
try:
time_since_insertion = (
datetime.datetime.now(datetime.timezone.utc)
- user["PasswordLastUsed"]
datetime.datetime.now()
- datetime.datetime.strptime(
user.password_last_used, "%Y-%m-%dT%H:%M:%S+00:00"
)
)
if time_since_insertion.days > maximum_expiration_days:
report.status = "FAIL"
report.status_extended = f"User {user['UserName']} has not logged into the console in the past 90 days"
report.status_extended = f"User {user.name} has not logged into the console in the past 90 days."
else:
report.status = "PASS"
report.status_extended = f"User {user['UserName']} has logged into the console in the past 90 days"
report.status_extended = f"User {user.name} has logged into the console in the past 90 days."
except KeyError:
pass
else:
report.status = "PASS"
report.status_extended = f"User {user['UserName']} has not a console password or is unused."
report.status_extended = (
f"User {user.name} has not a console password or is unused."
)
# Append report
findings.append(report)
else:
report = Check_Report(self.metadata)
report.status = "PASS"
report.status_extended = "There is no IAM users"
report.status_extended = "There is no IAM users."
report.region = "us-east-1"
findings.append(report)

View File

@@ -0,0 +1,48 @@
{
"Categories": [],
"CheckAlias": "check112",
"CheckID": "iam_no_root_access_key",
"CheckName": "iam_no_root_access_key",
"CheckTitle": "Ensure no root account access key exists",
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
"Compliance": [
{
"Control": [
"1.12"
],
"Framework": "CIS-AWS",
"Group": [
"level1"
],
"Version": "1.4"
}
],
"DependsOn": [],
"Description": "Ensure no root account access key exists",
"Notes": "",
"Provider": "aws",
"RelatedTo": [],
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Use the credential report to that the user and ensure the access_key_1_active and access_key_2_active fields are set to FALSE.",
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html"
}
},
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"ResourceType": "AwsIamUser",
"Risk": "The root account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the root account be removed. Removing access keys associated with the root account limits vectors by which the account can be compromised. Removing the root access keys encourages the creation and use of role based accounts that are least privileged.",
"ServiceName": "iam",
"Severity": "critical",
"SubServiceName": "",
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
}
}

View File

@@ -0,0 +1,37 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.iam.iam_service import iam_client
class iam_no_root_access_key(Check):
def execute(self) -> Check_Report:
findings = []
response = iam_client.credential_report
for user in response:
if user["user"] == "<root_account>":
report = Check_Report(self.metadata)
report.region = "us-east-1"
report.resource_id = user["user"]
report.resource_arn = user["arn"]
if (
user["access_key_1_active"] == "false"
and user["access_key_2_active"] == "false"
):
report.status = "PASS"
report.status_extended = f"User {user['user']} has not access keys."
elif (
user["access_key_1_active"] == "true"
and user["access_key_2_active"] == "true"
):
report.status = "FAIL"
report.status_extended = (
f"User {user['user']} has two active access keys."
)
else:
report.status = "FAIL"
report.status_extended = (
f"User {user['user']} has one active access key."
)
findings.append(report)
return findings

View File

@@ -0,0 +1,48 @@
{
"Categories": [],
"CheckAlias": "check114",
"CheckID": "iam_root_hardware_mfa_enabled",
"CheckName": "iam_root_hardware_mfa_enabled",
"CheckTitle": "Ensure hardware MFA is enabled for the root account",
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
"Compliance": [
{
"Control": [
"1.14"
],
"Framework": "CIS-AWS",
"Group": [
"level1"
],
"Version": "1.4"
}
],
"DependsOn": [],
"Description": "Ensure hardware MFA is enabled for the root account",
"Notes": "",
"Provider": "aws",
"RelatedTo": [],
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Using IAM console navigate to Dashboard and expand Activate MFA on your root account.",
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#id_root-user_manage_mfa"
}
},
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"ResourceType": "AwsIamUser",
"Risk": "The root account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled when a user signs in to an AWS website they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2 it is recommended that the root account be protected with a hardware MFA.",
"ServiceName": "iam",
"Severity": "critical",
"SubServiceName": "",
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
}
}

View File

@@ -0,0 +1,30 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.iam.iam_service import iam_client
class iam_root_hardware_mfa_enabled(Check):
def execute(self) -> Check_Report:
findings = []
virtual_mfa = False
report = Check_Report(self.metadata)
report.region = "us-east-1"
report.resource_id = "root"
report.resource_arn = f"arn:aws:iam::{iam_client.account}:root"
if iam_client.account_summary["SummaryMap"]["AccountMFAEnabled"] > 0:
virtual_mfas = iam_client.virtual_mfa_devices
for mfa in virtual_mfas:
if "root" in mfa["SerialNumber"]:
virtual_mfa = True
report.status = "FAIL"
report.status_extended = "Root account has a virtual MFA instead of a hardware MFA enabled."
if not virtual_mfa:
report.status = "PASS"
report.status_extended = "Root account has hardware MFA enabled."
else:
report.status = "FAIL"
report.status_extended = "MFA is not enabled for root account."
findings.append(report)
return findings

View File

@@ -0,0 +1,48 @@
{
"Categories": [],
"CheckAlias": "check113",
"CheckID": "iam_root_mfa_enabled",
"CheckName": "iam_root_mfa_enabled",
"CheckTitle": "Ensure MFA is enabled for the root account",
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
"Compliance": [
{
"Control": [
"1.13"
],
"Framework": "CIS-AWS",
"Group": [
"level1"
],
"Version": "1.4"
}
],
"DependsOn": [],
"Description": "Ensure MFA is enabled for the root account",
"Notes": "",
"Provider": "aws",
"RelatedTo": [],
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Using IAM console navigate to Dashboard and expand Activate MFA on your root account.",
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#id_root-user_manage_mfa"
}
},
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"ResourceType": "AwsIamUser",
"Risk": "The root account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled when a user signs in to an AWS website they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. When virtual MFA is used for root accounts it is recommended that the device used is NOT a personal device but rather a dedicated mobile device (tablet or phone) that is managed to be kept charged and secured independent of any individual personal devices. (non-personal virtual MFA) This lessens the risks of losing access to the MFA due to device loss / trade-in or if the individual owning the device is no longer employed at the company.",
"ServiceName": "iam",
"Severity": "critical",
"SubServiceName": "",
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
}
}

View File

@@ -0,0 +1,24 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.iam.iam_service import iam_client
class iam_root_mfa_enabled(Check):
def execute(self) -> Check_Report:
findings = []
if iam_client.credential_report:
for user in iam_client.credential_report:
if user["user"] == "<root_account>":
report = Check_Report(self.metadata)
report.region = "us-east-1"
report.resource_id = user["user"]
report.resource_arn = user["arn"]
if user["mfa_active"] == "false":
report.status = "FAIL"
report.status_extended = "MFA is not enabled for root account."
else:
report.status = "PASS"
report.status_extended = "MFA is enabled for root account."
findings.append(report)
return findings

View File

@@ -0,0 +1,48 @@
{
"Categories": [],
"CheckAlias": "check14",
"CheckID": "iam_rotate_access_key_90_days",
"CheckName": "iam_rotate_access_key_90_days",
"CheckTitle": "Ensure access keys are rotated every 90 days or less",
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
"Compliance": [
{
"Control": [
"1.4"
],
"Framework": "CIS-AWS",
"Group": [
"level1"
],
"Version": "1.4"
}
],
"DependsOn": [],
"Description": "Ensure access keys are rotated every 90 days or less",
"Notes": "",
"Provider": "aws",
"RelatedTo": [],
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Use the credential report to ensure access_key_X_last_rotated is less than 90 days ago.",
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html"
}
},
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"ResourceType": "AwsIamUser",
"Risk": "Access keys consist of an access key ID and secret access key which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI)- Tools for Windows PowerShell- the AWS SDKs- or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated.",
"ServiceName": "iam",
"Severity": "medium",
"SubServiceName": "",
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
}
}

View File

@@ -0,0 +1,63 @@
import datetime
from lib.check.models import Check, Check_Report
from providers.aws.services.iam.iam_service import iam_client
maximum_expiration_days = 90
class iam_rotate_access_key_90_days(Check):
def execute(self) -> Check_Report:
findings = []
response = iam_client.credential_report
if response:
for user in response:
report = Check_Report(self.metadata)
report.region = "us-east-1"
report.resource_id = user["user"]
report.resource_arn = user["arn"]
if (
user["access_key_1_last_rotated"] == "N/A"
and user["access_key_2_last_rotated"] == "N/A"
):
report.status = "PASS"
report.status_extended = f"User {user['user']} has not access keys."
else:
old_access_keys = False
if user["access_key_1_last_rotated"] != "N/A":
access_key_1_last_rotated = (
datetime.datetime.now()
- datetime.datetime.strptime(
user["access_key_1_last_rotated"],
"%Y-%m-%dT%H:%M:%S+00:00",
)
)
if access_key_1_last_rotated.days > maximum_expiration_days:
old_access_keys = True
report.status = "FAIL"
report.status_extended = f"User {user['user']} has not rotated access key 1 in over 90 days ({access_key_1_last_rotated.days} days)."
if user["access_key_2_last_rotated"] != "N/A":
access_key_2_last_rotated = (
datetime.datetime.now()
- datetime.datetime.strptime(
user["access_key_2_last_rotated"],
"%Y-%m-%dT%H:%M:%S+00:00",
)
)
if access_key_2_last_rotated.days > maximum_expiration_days:
old_access_keys = True
report.status = "FAIL"
report.status_extended = f"User {user['user']} has not rotated access key 2 in over 90 days ({access_key_2_last_rotated.days} days)."
if not old_access_keys:
report.status = "PASS"
report.status_extended = f"User {user['user']} has access keys not older than 90 days."
findings.append(report)
else:
report = Check_Report(self.metadata)
report.status = "PASS"
report.status_extended = "There is no IAM users."
report.region = "us-east-1"
findings.append(report)
return findings

View File

@@ -1,4 +1,5 @@
import sys
import csv
from dataclasses import dataclass
from lib.logger import logger
from providers.aws.aws_provider import current_audit_info
@@ -9,13 +10,19 @@ class IAM:
def __init__(self, audit_info):
self.service = "iam"
self.session = audit_info.audit_session
self.account = audit_info.audited_account
self.client = self.session.client(self.service)
self.region = audit_info.profile_region
self.users = self.__get_users__()
self.roles = self.__get_roles__()
self.account_summary = self.__get_account_summary__()
self.virtual_mfa_devices = self.__list_virtual_mfa_devices__()
self.customer_managed_policies = self.__get_customer_managed_policies__()
self.credential_report = self.__get_credential_report__()
self.groups = self.__get_groups__()
self.__get_group_users__()
self.__list_attached_group_policies__()
self.__list_mfa_devices__()
def __get_client__(self):
return self.client
@@ -47,7 +54,12 @@ class IAM:
if report_status["State"] == "COMPLETE":
report_is_completed = True
return self.client.get_credential_report()
# Convert credential report to list of dictionaries
credential = self.client.get_credential_report()["Content"].decode("utf-8")
credential_lines = credential.split("\n")
csv_reader = csv.DictReader(credential_lines, delimiter=",")
credential_list = list(csv_reader)
return credential_list
def __get_groups__(self):
try:
@@ -58,7 +70,7 @@ class IAM:
groups = []
for page in get_groups_paginator.paginate():
for group in page["Groups"]:
groups.append(group)
groups.append(Group(group["GroupName"], group["Arn"]))
return groups
@@ -77,6 +89,15 @@ class IAM:
return customer_managed_policies
def __get_account_summary__(self):
try:
account_summary = self.client.get_account_summary()
except Exception as error:
logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
else:
return account_summary
def __get_users__(self):
try:
get_users_paginator = self.client.get_paginator("list_users")
@@ -86,13 +107,127 @@ class IAM:
users = []
for page in get_users_paginator.paginate():
for user in page["Users"]:
users.append(user)
if "PasswordLastUsed" not in user:
users.append(User(user["UserName"], user["Arn"], None))
else:
users.append(
User(
user["UserName"], user["Arn"], user["PasswordLastUsed"]
)
)
return users
def __list_virtual_mfa_devices__(self):
try:
list_virtual_mfa_devices_paginator = self.client.get_paginator(
"list_virtual_mfa_devices"
)
except Exception as error:
logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
else:
mfa_devices = []
for page in list_virtual_mfa_devices_paginator.paginate():
for mfa_device in page["VirtualMFADevices"]:
mfa_devices.append(mfa_device)
try:
iam_client = IAM(current_audit_info)
except Exception as error:
logger.critical(f"{error.__class__.__name__} -- {error}")
sys.exit()
return mfa_devices
def __list_attached_group_policies__(self):
try:
for group in self.groups:
list_attached_group_policies_paginator = self.client.get_paginator(
"list_attached_group_policies"
)
attached_group_policies = []
for page in list_attached_group_policies_paginator.paginate(
GroupName=group.name
):
for attached_group_policy in page["AttachedPolicies"]:
attached_group_policies.append(attached_group_policy)
group.attached_policies = attached_group_policies
except Exception as error:
logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
def __get_group_users__(self):
try:
for group in self.groups:
get_group_paginator = self.client.get_paginator("get_group")
group_users = []
for page in get_group_paginator.paginate(GroupName=group.name):
for user in page["Users"]:
if "PasswordLastUsed" not in user:
group_users.append(
User(user["UserName"], user["Arn"], None)
)
else:
group_users.append(
User(
user["UserName"],
user["Arn"],
user["PasswordLastUsed"],
)
)
group.users = group_users
except Exception as error:
logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
def __list_mfa_devices__(self):
try:
for user in self.users:
list_mfa_devices_paginator = self.client.get_paginator(
"list_mfa_devices"
)
mfa_devices = []
for page in list_mfa_devices_paginator.paginate(UserName=user.name):
for mfa_device in page["MFADevices"]:
mfa_serial_number = mfa_device["SerialNumber"]
mfa_type = (
mfa_device["SerialNumber"].split(":")[5].split("/")[0]
)
mfa_devices.append(MFADevice(mfa_serial_number, mfa_type))
user.mfa_devices = mfa_devices
except Exception as error:
logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
@dataclass
class MFADevice:
serial_number: str
type: str
def __init__(self, serial_number, type):
self.serial_number = serial_number
self.type = type
@dataclass
class User:
name: str
arn: str
mfa_devices: list[MFADevice]
password_last_used: str
def __init__(self, name, arn, password_last_used):
self.name = name
self.arn = arn
self.password_last_used = password_last_used
self.mfa_devices = []
@dataclass
class Group:
name: str
arn: str
attached_policies: list[dict]
users: list[User]
def __init__(self, name, arn):
self.name = name
self.arn = arn
self.attached_policies = []
self.users = []
iam_client = IAM(current_audit_info)

View File

@@ -0,0 +1,37 @@
{
"Categories": [],
"CheckAlias": "extra7125",
"CheckID": "iam_user_hardware_mfa_enabled",
"CheckName": "iam_user_hardware_mfa_enabled",
"CheckTitle": "Check if IAM users have Hardware MFA enabled.",
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
"Compliance": [],
"DependsOn": [],
"Description": "Check if IAM users have Hardware MFA enabled.",
"Notes": "",
"Provider": "aws",
"RelatedTo": [],
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable hardware MFA device for an IAM user from the AWS Management Console; the command line; or the IAM API.",
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_physical.html"
}
},
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"ResourceType": "AwsIamUser",
"Risk": "Hardware MFA is preferred over virtual MFA.",
"ServiceName": "iam",
"Severity": "medium",
"SubServiceName": "",
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
}
}

View File

@@ -0,0 +1,41 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.iam.iam_service import iam_client
class iam_user_hardware_mfa_enabled(Check):
def execute(self) -> Check_Report:
findings = []
response = iam_client.users
if response:
for user in response:
report = Check_Report(self.metadata)
report.resource_id = user.name
report.resource_arn = user.arn
report.region = "us-east-1"
if user.mfa_devices:
for mfa_device in user.mfa_devices:
if mfa_device.type == "mfa" or mfa_device.type == "sms-mfa":
report.status = "FAIL"
report.status_extended = f"User {user.name} has a virtual MFA instead of a hardware MFA enabled."
findings.append(report)
else:
report.status = "PASS"
report.status_extended = (
f"User {user.name} has hardware MFA enabled."
)
findings.append(report)
else:
report.status = "FAIL"
report.status_extended = (
f"User {user.name} has not any type of MFA enabled."
)
findings.append(report)
else:
report = Check_Report(self.metadata)
report.status = "PASS"
report.status_extended = "There is no IAM users."
report.region = iam_client.region
findings.append(report)
return findings

View File

@@ -0,0 +1,37 @@
{
"Categories": [],
"CheckAlias": "check12",
"CheckID": "iam_user_mfa_enabled_console_access",
"CheckName": "iam_user_mfa_enabled_console_access",
"CheckTitle": "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password.",
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
"Compliance": [],
"DependsOn": [],
"Description": "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password.",
"Notes": "",
"Provider": "aws",
"RelatedTo": [],
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable MFA for users account. MFA is a simple best practice that adds an extra layer of protection on top of your user name and password. Recommended to use hardware keys over virtual MFA.",
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html"
}
},
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"ResourceType": "AwsIamUser",
"Risk": "Unauthorized access to this critical account if password is not secure or it is disclosed in any way.",
"ServiceName": "iam",
"Severity": "high",
"SubServiceName": "",
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
}
}

View File

@@ -0,0 +1,36 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.iam.iam_service import iam_client
class iam_user_mfa_enabled_console_access(Check):
def execute(self) -> Check_Report:
findings = []
response = iam_client.credential_report
if response:
for user in response:
report = Check_Report(self.metadata)
report.resource_id = user["user"]
report.resource_arn = user["arn"]
report.region = "us-east-1"
if user["password_enabled"] != "not_supported":
if user["mfa_active"] == "false":
report.status = "FAIL"
report.status_extended = f"User {user['user']} has Console Password enabled but MFA disabled."
else:
report.status = "PASS"
report.status_extended = f"User {user['user']} has Console Password enabled and MFA enabled."
else:
report.status = "PASS"
report.status_extended = (
f"User {user['user']} has not Console Password enabled."
)
findings.append(report)
else:
report = Check_Report(self.metadata)
report.status = "PASS"
report.status_extended = "There is no IAM users."
report.region = iam_client.region
findings.append(report)
return findings

View File

@@ -0,0 +1,37 @@
{
"Categories": [],
"CheckAlias": "extra7123",
"CheckID": "iam_user_two_active_access_key",
"CheckName": "iam_user_two_active_access_key",
"CheckTitle": "Check if IAM users have two active access keys",
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
"Compliance": [],
"DependsOn": [],
"Description": "Check if IAM users have two active access keys",
"Notes": "",
"Provider": "aws",
"RelatedTo": [],
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Avoid using long lived access keys.",
"Url": "https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAccessKeys.html"
}
},
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"ResourceType": "AwsIamUser",
"Risk": "Access Keys could be lost or stolen. It creates a critical risk.",
"ServiceName": "iam",
"Severity": "medium",
"SubServiceName": "",
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
}
}

View File

@@ -0,0 +1,38 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.iam.iam_service import iam_client
class iam_user_two_active_access_key(Check):
def execute(self) -> Check_Report:
findings = []
response = iam_client.credential_report
if response:
for user in response:
report = Check_Report(self.metadata)
report.resource_id = user["user"]
report.resource_arn = user["arn"]
report.region = "us-east-1"
if (
user["access_key_1_active"] == "true"
and user["access_key_2_active"] == "true"
):
report.status = "FAIL"
report.status_extended = (
f"User {user['user']} has 2 active access keys."
)
findings.append(report)
else:
report.status = "PASS"
report.status_extended = (
f"User {user['user']} has not 2 active access keys."
)
findings.append(report)
else:
report = Check_Report(self.metadata)
report.status = "PASS"
report.status_extended = "There is no IAM users."
report.region = iam_client.region
findings.append(report)
return findings