From ed1572d2d9a408915daca4f6ea8229b265b41dbe Mon Sep 17 00:00:00 2001 From: Sergio Garcia <38561120+sergargar@users.noreply.github.com> Date: Fri, 22 Jul 2022 12:14:49 +0200 Subject: [PATCH] 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 --- Pipfile | 2 +- Pipfile.lock | 174 +++++++++--------- lib/outputs/models.py | 7 +- .../__init__.py | 0 ...dministrator_access_with_mfa.metadata.json | 37 ++++ .../iam_administrator_access_with_mfa.py | 64 +++++++ .../iam/iam_avoid_root_usage/__init__.py | 0 .../iam_avoid_root_usage.metadata.json | 48 +++++ .../iam_avoid_root_usage.py | 61 ++++++ ..._disable_30_days_credentials.metadata.json | 53 ++---- .../iam_disable_30_days_credentials.py | 24 ++- ..._disable_90_days_credentials.metadata.json | 44 ++--- .../iam_disable_90_days_credentials.py | 24 ++- .../iam/iam_no_root_access_key/__init__.py | 0 .../iam_no_root_access_key.metadata.json | 48 +++++ .../iam_no_root_access_key.py | 37 ++++ .../iam_root_hardware_mfa_enabled/__init__.py | 0 ...am_root_hardware_mfa_enabled.metadata.json | 48 +++++ .../iam_root_hardware_mfa_enabled.py | 30 +++ .../iam/iam_root_mfa_enabled/__init__.py | 0 .../iam_root_mfa_enabled.metadata.json | 48 +++++ .../iam_root_mfa_enabled.py | 24 +++ .../iam_rotate_access_key_90_days/__init__.py | 0 ...am_rotate_access_key_90_days.metadata.json | 48 +++++ .../iam_rotate_access_key_90_days.py | 63 +++++++ providers/aws/services/iam/iam_service.py | 153 ++++++++++++++- .../iam_user_hardware_mfa_enabled/__init__.py | 0 ...am_user_hardware_mfa_enabled.metadata.json | 37 ++++ .../iam_user_hardware_mfa_enabled.py | 41 +++++ .../__init__.py | 0 ...r_mfa_enabled_console_access.metadata.json | 37 ++++ .../iam_user_mfa_enabled_console_access.py | 36 ++++ .../__init__.py | 0 ...m_user_two_active_access_key.metadata.json | 37 ++++ .../iam_user_two_active_access_key.py | 38 ++++ 35 files changed, 1077 insertions(+), 186 deletions(-) create mode 100644 providers/aws/services/iam/iam_administrator_access_with_mfa/__init__.py create mode 100644 providers/aws/services/iam/iam_administrator_access_with_mfa/iam_administrator_access_with_mfa.metadata.json create mode 100644 providers/aws/services/iam/iam_administrator_access_with_mfa/iam_administrator_access_with_mfa.py create mode 100644 providers/aws/services/iam/iam_avoid_root_usage/__init__.py create mode 100644 providers/aws/services/iam/iam_avoid_root_usage/iam_avoid_root_usage.metadata.json create mode 100644 providers/aws/services/iam/iam_avoid_root_usage/iam_avoid_root_usage.py create mode 100644 providers/aws/services/iam/iam_no_root_access_key/__init__.py create mode 100644 providers/aws/services/iam/iam_no_root_access_key/iam_no_root_access_key.metadata.json create mode 100644 providers/aws/services/iam/iam_no_root_access_key/iam_no_root_access_key.py create mode 100644 providers/aws/services/iam/iam_root_hardware_mfa_enabled/__init__.py create mode 100644 providers/aws/services/iam/iam_root_hardware_mfa_enabled/iam_root_hardware_mfa_enabled.metadata.json create mode 100644 providers/aws/services/iam/iam_root_hardware_mfa_enabled/iam_root_hardware_mfa_enabled.py create mode 100644 providers/aws/services/iam/iam_root_mfa_enabled/__init__.py create mode 100644 providers/aws/services/iam/iam_root_mfa_enabled/iam_root_mfa_enabled.metadata.json create mode 100644 providers/aws/services/iam/iam_root_mfa_enabled/iam_root_mfa_enabled.py create mode 100644 providers/aws/services/iam/iam_rotate_access_key_90_days/__init__.py create mode 100644 providers/aws/services/iam/iam_rotate_access_key_90_days/iam_rotate_access_key_90_days.metadata.json create mode 100644 providers/aws/services/iam/iam_rotate_access_key_90_days/iam_rotate_access_key_90_days.py create mode 100644 providers/aws/services/iam/iam_user_hardware_mfa_enabled/__init__.py create mode 100644 providers/aws/services/iam/iam_user_hardware_mfa_enabled/iam_user_hardware_mfa_enabled.metadata.json create mode 100644 providers/aws/services/iam/iam_user_hardware_mfa_enabled/iam_user_hardware_mfa_enabled.py create mode 100644 providers/aws/services/iam/iam_user_mfa_enabled_console_access/__init__.py create mode 100644 providers/aws/services/iam/iam_user_mfa_enabled_console_access/iam_user_mfa_enabled_console_access.metadata.json create mode 100644 providers/aws/services/iam/iam_user_mfa_enabled_console_access/iam_user_mfa_enabled_console_access.py create mode 100644 providers/aws/services/iam/iam_user_two_active_access_key/__init__.py create mode 100644 providers/aws/services/iam/iam_user_two_active_access_key/iam_user_two_active_access_key.metadata.json create mode 100644 providers/aws/services/iam/iam_user_two_active_access_key/iam_user_two_active_access_key.py diff --git a/Pipfile b/Pipfile index 8468a4b3..6579dfc0 100644 --- a/Pipfile +++ b/Pipfile @@ -20,4 +20,4 @@ pytest = "7.1.2" [dev-packages] [requires] -python_version = "3.9" +python_version = "3" diff --git a/Pipfile.lock b/Pipfile.lock index 7e356211..fed3e550 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -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": [ diff --git a/lib/outputs/models.py b/lib/outputs/models.py index 51a6b5f2..6c2c183c 100644 --- a/lib/outputs/models.py +++ b/lib/outputs/models.py @@ -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) diff --git a/providers/aws/services/iam/iam_administrator_access_with_mfa/__init__.py b/providers/aws/services/iam/iam_administrator_access_with_mfa/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_administrator_access_with_mfa/iam_administrator_access_with_mfa.metadata.json b/providers/aws/services/iam/iam_administrator_access_with_mfa/iam_administrator_access_with_mfa.metadata.json new file mode 100644 index 00000000..0e2916bb --- /dev/null +++ b/providers/aws/services/iam/iam_administrator_access_with_mfa/iam_administrator_access_with_mfa.metadata.json @@ -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" + } +} diff --git a/providers/aws/services/iam/iam_administrator_access_with_mfa/iam_administrator_access_with_mfa.py b/providers/aws/services/iam/iam_administrator_access_with_mfa/iam_administrator_access_with_mfa.py new file mode 100644 index 00000000..c7476c66 --- /dev/null +++ b/providers/aws/services/iam/iam_administrator_access_with_mfa/iam_administrator_access_with_mfa.py @@ -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 diff --git a/providers/aws/services/iam/iam_avoid_root_usage/__init__.py b/providers/aws/services/iam/iam_avoid_root_usage/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_avoid_root_usage/iam_avoid_root_usage.metadata.json b/providers/aws/services/iam/iam_avoid_root_usage/iam_avoid_root_usage.metadata.json new file mode 100644 index 00000000..39e6dc4a --- /dev/null +++ b/providers/aws/services/iam/iam_avoid_root_usage/iam_avoid_root_usage.metadata.json @@ -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" + } +} diff --git a/providers/aws/services/iam/iam_avoid_root_usage/iam_avoid_root_usage.py b/providers/aws/services/iam/iam_avoid_root_usage/iam_avoid_root_usage.py new file mode 100644 index 00000000..ebd4c83a --- /dev/null +++ b/providers/aws/services/iam/iam_avoid_root_usage/iam_avoid_root_usage.py @@ -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"] == "": + 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 diff --git a/providers/aws/services/iam/iam_disable_30_days_credentials/iam_disable_30_days_credentials.metadata.json b/providers/aws/services/iam/iam_disable_30_days_credentials/iam_disable_30_days_credentials.metadata.json index bb970fdd..1839c825 100644 --- a/providers/aws/services/iam/iam_disable_30_days_credentials/iam_disable_30_days_credentials.metadata.json +++ b/providers/aws/services/iam/iam_disable_30_days_credentials/iam_disable_30_days_credentials.metadata.json @@ -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" diff --git a/providers/aws/services/iam/iam_disable_30_days_credentials/iam_disable_30_days_credentials.py b/providers/aws/services/iam/iam_disable_30_days_credentials/iam_disable_30_days_credentials.py index 820bc095..dbcde3e1 100644 --- a/providers/aws/services/iam/iam_disable_30_days_credentials/iam_disable_30_days_credentials.py +++ b/providers/aws/services/iam/iam_disable_30_days_credentials/iam_disable_30_days_credentials.py @@ -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) diff --git a/providers/aws/services/iam/iam_disable_90_days_credentials/iam_disable_90_days_credentials.metadata.json b/providers/aws/services/iam/iam_disable_90_days_credentials/iam_disable_90_days_credentials.metadata.json index 75388b1d..966ca26a 100644 --- a/providers/aws/services/iam/iam_disable_90_days_credentials/iam_disable_90_days_credentials.metadata.json +++ b/providers/aws/services/iam/iam_disable_90_days_credentials/iam_disable_90_days_credentials.metadata.json @@ -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" diff --git a/providers/aws/services/iam/iam_disable_90_days_credentials/iam_disable_90_days_credentials.py b/providers/aws/services/iam/iam_disable_90_days_credentials/iam_disable_90_days_credentials.py index 8d96d3fb..2543273b 100644 --- a/providers/aws/services/iam/iam_disable_90_days_credentials/iam_disable_90_days_credentials.py +++ b/providers/aws/services/iam/iam_disable_90_days_credentials/iam_disable_90_days_credentials.py @@ -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) diff --git a/providers/aws/services/iam/iam_no_root_access_key/__init__.py b/providers/aws/services/iam/iam_no_root_access_key/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_no_root_access_key/iam_no_root_access_key.metadata.json b/providers/aws/services/iam/iam_no_root_access_key/iam_no_root_access_key.metadata.json new file mode 100644 index 00000000..cb3452d0 --- /dev/null +++ b/providers/aws/services/iam/iam_no_root_access_key/iam_no_root_access_key.metadata.json @@ -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" + } +} diff --git a/providers/aws/services/iam/iam_no_root_access_key/iam_no_root_access_key.py b/providers/aws/services/iam/iam_no_root_access_key/iam_no_root_access_key.py new file mode 100644 index 00000000..41f5bbe2 --- /dev/null +++ b/providers/aws/services/iam/iam_no_root_access_key/iam_no_root_access_key.py @@ -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"] == "": + 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 diff --git a/providers/aws/services/iam/iam_root_hardware_mfa_enabled/__init__.py b/providers/aws/services/iam/iam_root_hardware_mfa_enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_root_hardware_mfa_enabled/iam_root_hardware_mfa_enabled.metadata.json b/providers/aws/services/iam/iam_root_hardware_mfa_enabled/iam_root_hardware_mfa_enabled.metadata.json new file mode 100644 index 00000000..a7487e20 --- /dev/null +++ b/providers/aws/services/iam/iam_root_hardware_mfa_enabled/iam_root_hardware_mfa_enabled.metadata.json @@ -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" + } +} diff --git a/providers/aws/services/iam/iam_root_hardware_mfa_enabled/iam_root_hardware_mfa_enabled.py b/providers/aws/services/iam/iam_root_hardware_mfa_enabled/iam_root_hardware_mfa_enabled.py new file mode 100644 index 00000000..fce43beb --- /dev/null +++ b/providers/aws/services/iam/iam_root_hardware_mfa_enabled/iam_root_hardware_mfa_enabled.py @@ -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 diff --git a/providers/aws/services/iam/iam_root_mfa_enabled/__init__.py b/providers/aws/services/iam/iam_root_mfa_enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_root_mfa_enabled/iam_root_mfa_enabled.metadata.json b/providers/aws/services/iam/iam_root_mfa_enabled/iam_root_mfa_enabled.metadata.json new file mode 100644 index 00000000..9787604d --- /dev/null +++ b/providers/aws/services/iam/iam_root_mfa_enabled/iam_root_mfa_enabled.metadata.json @@ -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" + } +} diff --git a/providers/aws/services/iam/iam_root_mfa_enabled/iam_root_mfa_enabled.py b/providers/aws/services/iam/iam_root_mfa_enabled/iam_root_mfa_enabled.py new file mode 100644 index 00000000..23543546 --- /dev/null +++ b/providers/aws/services/iam/iam_root_mfa_enabled/iam_root_mfa_enabled.py @@ -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"] == "": + 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 diff --git a/providers/aws/services/iam/iam_rotate_access_key_90_days/__init__.py b/providers/aws/services/iam/iam_rotate_access_key_90_days/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_rotate_access_key_90_days/iam_rotate_access_key_90_days.metadata.json b/providers/aws/services/iam/iam_rotate_access_key_90_days/iam_rotate_access_key_90_days.metadata.json new file mode 100644 index 00000000..a3b0d158 --- /dev/null +++ b/providers/aws/services/iam/iam_rotate_access_key_90_days/iam_rotate_access_key_90_days.metadata.json @@ -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" + } +} diff --git a/providers/aws/services/iam/iam_rotate_access_key_90_days/iam_rotate_access_key_90_days.py b/providers/aws/services/iam/iam_rotate_access_key_90_days/iam_rotate_access_key_90_days.py new file mode 100644 index 00000000..f90447ed --- /dev/null +++ b/providers/aws/services/iam/iam_rotate_access_key_90_days/iam_rotate_access_key_90_days.py @@ -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 diff --git a/providers/aws/services/iam/iam_service.py b/providers/aws/services/iam/iam_service.py index f5fef8d1..366771e2 100644 --- a/providers/aws/services/iam/iam_service.py +++ b/providers/aws/services/iam/iam_service.py @@ -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) diff --git a/providers/aws/services/iam/iam_user_hardware_mfa_enabled/__init__.py b/providers/aws/services/iam/iam_user_hardware_mfa_enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_user_hardware_mfa_enabled/iam_user_hardware_mfa_enabled.metadata.json b/providers/aws/services/iam/iam_user_hardware_mfa_enabled/iam_user_hardware_mfa_enabled.metadata.json new file mode 100644 index 00000000..7c328860 --- /dev/null +++ b/providers/aws/services/iam/iam_user_hardware_mfa_enabled/iam_user_hardware_mfa_enabled.metadata.json @@ -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" + } +} diff --git a/providers/aws/services/iam/iam_user_hardware_mfa_enabled/iam_user_hardware_mfa_enabled.py b/providers/aws/services/iam/iam_user_hardware_mfa_enabled/iam_user_hardware_mfa_enabled.py new file mode 100644 index 00000000..1dd9dfa3 --- /dev/null +++ b/providers/aws/services/iam/iam_user_hardware_mfa_enabled/iam_user_hardware_mfa_enabled.py @@ -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 diff --git a/providers/aws/services/iam/iam_user_mfa_enabled_console_access/__init__.py b/providers/aws/services/iam/iam_user_mfa_enabled_console_access/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_user_mfa_enabled_console_access/iam_user_mfa_enabled_console_access.metadata.json b/providers/aws/services/iam/iam_user_mfa_enabled_console_access/iam_user_mfa_enabled_console_access.metadata.json new file mode 100644 index 00000000..de6664b8 --- /dev/null +++ b/providers/aws/services/iam/iam_user_mfa_enabled_console_access/iam_user_mfa_enabled_console_access.metadata.json @@ -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" + } +} diff --git a/providers/aws/services/iam/iam_user_mfa_enabled_console_access/iam_user_mfa_enabled_console_access.py b/providers/aws/services/iam/iam_user_mfa_enabled_console_access/iam_user_mfa_enabled_console_access.py new file mode 100644 index 00000000..401444bd --- /dev/null +++ b/providers/aws/services/iam/iam_user_mfa_enabled_console_access/iam_user_mfa_enabled_console_access.py @@ -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 diff --git a/providers/aws/services/iam/iam_user_two_active_access_key/__init__.py b/providers/aws/services/iam/iam_user_two_active_access_key/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_user_two_active_access_key/iam_user_two_active_access_key.metadata.json b/providers/aws/services/iam/iam_user_two_active_access_key/iam_user_two_active_access_key.metadata.json new file mode 100644 index 00000000..ed916dc8 --- /dev/null +++ b/providers/aws/services/iam/iam_user_two_active_access_key/iam_user_two_active_access_key.metadata.json @@ -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" + } +} diff --git a/providers/aws/services/iam/iam_user_two_active_access_key/iam_user_two_active_access_key.py b/providers/aws/services/iam/iam_user_two_active_access_key/iam_user_two_active_access_key.py new file mode 100644 index 00000000..e933ddc0 --- /dev/null +++ b/providers/aws/services/iam/iam_user_two_active_access_key/iam_user_two_active_access_key.py @@ -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