From 9f66ca4053c513b085c6750307f3f68e1bbaf3da Mon Sep 17 00:00:00 2001 From: "mariano.pizarro" Date: Tue, 3 May 2022 17:07:19 -0300 Subject: [PATCH 1/4] feat: Included 1.x rules for aws cis 1.4.0 --- src/aws/cis-1.4.0/README.md | 25 +- src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.10.ts | 94 ++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.12.ts | 124 +++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.13.ts | 92 ++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.14.ts | 116 +++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.15.ts | 83 ++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.16.ts | 102 +++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.17.ts | 105 +++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.19.ts | 68 ++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.21.ts | 43 + src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.4.ts | 62 ++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.5.ts | 60 ++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.6.ts | 79 ++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.7.ts | 70 ++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.8.ts | 62 ++ src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.9.ts | 61 ++ src/aws/cis-1.4.0/rules/index.ts | 32 +- .../cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts | 851 ++++++++++++++++++ src/aws/cis-1.4.0/tests/aws-cis-1.4.0.test.ts | 19 - 19 files changed, 2120 insertions(+), 28 deletions(-) create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.10.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.12.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.13.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.14.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.15.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.16.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.17.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.19.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.21.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.4.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.5.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.6.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.7.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.8.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.9.ts create mode 100644 src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts delete mode 100644 src/aws/cis-1.4.0/tests/aws-cis-1.4.0.test.ts diff --git a/src/aws/cis-1.4.0/README.md b/src/aws/cis-1.4.0/README.md index 56ce3f12..18cc44a7 100644 --- a/src/aws/cis-1.4.0/README.md +++ b/src/aws/cis-1.4.0/README.md @@ -53,11 +53,20 @@ Policy Pack based on the [AWS Foundations 1.4.0](https://docs.aws.amazon.com/aud } ``` - +| Rule | Description | +| ------------- | --------------------------------------------------------------------------------------------------------------------------- | +| AWS CIS 1.4 | Ensure no 'root' user account access key exists | +| AWS CIS 1.5 | Ensure MFA is enabled for the 'root' user account | +| AWS CIS 1.6 | Ensure hardware MFA is enabled for the 'root' user account | +| AWS CIS 1.7 | Eliminate use of the 'root' user for administrative and daily tasks | +| AWS CIS 1.8 | Ensure IAM password policy requires minimum length of 14 or greater | +| AWS CIS 1.9 | Ensure IAM password policy prevents password reuse | +| AWS CIS 1.10 | Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password | +| AWS CIS 1.12 | Ensure credentials unused for 45 days or greater are disabled | +| AWS CIS 1.13 | Ensure there is only one active access key available for any single IAM user | +| AWS CIS 1.14 | Ensure access keys are rotated every 90 days or less | +| AWS CIS 1.15 | Ensure IAM Users Receive Permissions Only Through Groups | +| AWS CIS 1.16 | Ensure IAM policies that allow full "*:*" administrative privileges are not attached | +| AWS CIS 1.17 | Ensure a support role has been created to manage incidents with AWS Support | +| AWS CIS 1.19 | Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed | +| AWS CIS 1.21 | Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments (Manual) | diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.10.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.10.ts new file mode 100644 index 00000000..772b5fea --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.10.ts @@ -0,0 +1,94 @@ +// AWS CIS 1.2.0 Rule equivalent 1.2 +export default { + id: 'aws-cis-1.4.0-1.10', + title: 'AWS CIS 1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password', + + description: 'Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.', + + audit: `Perform the following to determine if a MFA device is enabled for all IAM users having a console password: + + **From Console:** + + 1. Open the IAM console at https://console.aws.amazon.com/iam/. + 2. In the left pane, select *Users* + 3. If the *MFA* or *Password age* columns are not visible in the table, click the gear icon at the upper right corner of the table and ensure a checkmark is next to both, then click *Close*. + 4. Ensure that for each user where the *Password age* column shows a password age, the MFA column shows *Virtual*, *U2F Security Key*, or *Hardware*. + + **From Command Line:** + + 1. Run the following command (OSX/Linux/UNIX) to generate a list of all IAM users along with their password and MFA status: + + aws iam generate-credential-report + + aws iam get-credential-report --query 'Content' --output text | base64 -d | cut -d, -f1,4,8 + + 2. The output of this command will produce a table similar to the following: + + user,password_enabled,mfa_active + elise,false,false + brandon,true,true + rakesh,false,false + helene,false,false + paras,true,true + anitha,false,false + + 3. For any column having *password_enabled* set to *true*, ensure *mfa_active* is also set to *true*.`, + + rationale: 'Enabling MFA provides increased security for console access as it requires the authenticating principal to possess a device that displays a time-sensitive key and have knowledge of a credential.', + + remediation: `Perform the following to enable MFA: + + **From Console:** + + 1. Sign in to the AWS Management Console and open the IAM console at 'https://console.aws.amazon.com/iam/' + 2. In the left pane, select *Users*. + 3. In the *User Name* list, choose the name of the intended MFA user. + 4. Choose the *Security Credentials* tab, and then choose *Manage MFA Device*. + 5. In the *Manage MFA Device wizard*, choose *Virtual MFA* device, and then choose *Continue*. + + IAM generates and displays configuration information for the virtual MFA device, including a QR code graphic. The graphic is a representation of the 'secret configuration key' that is available for manual entry on devices that do not support QR codes. + + 6. Open your virtual MFA application. (For a list of apps that you can use for hosting virtual MFA devices, see Virtual MFA Applications at https://aws.amazon.com/iam/details/mfa/#Virtual_MFA_Applications). If the virtual MFA application supports multiple accounts (multiple virtual MFA devices), choose the option to create a new account (a new virtual MFA device). + 7. Determine whether the MFA app supports QR codes, and then do one of the following: + + - Use the app to scan the QR code. For example, you might choose the camera icon or choose an option similar to Scan code, and then use the device's camera to scan the code. + - In the Manage MFA Device wizard, choose Show secret key for manual configuration, and then type the secret configuration key into your MFA application. + + When you are finished, the virtual MFA device starts generating one-time passwords. + + 8. In the *Manage MFA Device wizard*, in the *MFA Code 1 box*, type the *one-time password* that currently appears in the virtual MFA device. Wait up to 30 seconds for the device to generate a new one-time password. Then type the second *one-time password* into the *MFA Code 2 box*. + 9. Click *Assign MFA*.`, + + references: [ + 'https://tools.ietf.org/html/rfc6238', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa.html', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#enable-mfa-for-privileged-users', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html', + 'CCE-78901-6', + 'https://blogs.aws.amazon.com/security/post/Tx2SJJYE082KBUK/How-to-Delegate-Management-of-Multi-Factor-Authentication-to-AWS-IAM-Users', + ], + gql: `{ + queryawsIamUser { + id + arn + accountId + __typename + passwordEnabled + mfaActive + } + }`, + resource: 'queryawsIamUser[*]', + severity: 'high', + conditions: { + or: [ + { + path: '@.passwordEnabled', + equal: false, + }, + { + path: '@.mfaActive', + equal: true, + } + ] + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.12.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.12.ts new file mode 100644 index 00000000..44ee6f3c --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.12.ts @@ -0,0 +1,124 @@ +// AWS CIS 1.2.0 Rule equivalent 1.3 +export default { + id: 'aws-cis-1.4.0-1.12', + title: 'AWS CIS 1.12 Ensure credentials unused for 45 days or greater are disabled', + + description: 'AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed.', + + audit: `Perform the following to determine if unused credentials exist: + + **From Console:** + + 1. Login to the AWS Management Console + 2. Click *Services* + 3. Click *IAM* + 4. Click on *Users* + 5. Click the *Settings* (gear) icon. + 6. Select *Console last sign-in*, *Access key last used*, and *Access Key Id* + 7. Click on *Close* + 8. Check and ensure that *Console last sign-in* is less than 45 days ago. + + **Note** - *Never* means the user has never logged in. + + 9. Check and ensure that *Access key age* is less than 45 days and that *Access key last used* does not say *None* + + If the user hasn't signed into the Console in the last 45 days or Access keys are over 45 days old refer to the remediation. + + **From Command Line:** + **Download Credential Report:** + + 1. Run the following commands: + + aws iam generate-credential-report + + aws iam get-credential-report --query 'Content' --output text | base64 -d | cut -d, -f1,4,5,6,9,10,11,14,15,16 + + **Ensure unused credentials do not exist:** + + 2. For each user having *password_enabled* set to *TRUE*, ensure *password_last_used_date* is less than *45* days ago. + + - When *password_enabled* is set to *TRUE* and password_last_used is set to No_Information , ensure *password_last_changed* is less than *45* days ago. + + 3. For each user having an *access_key_1_active* or *access_key_2_active* to *TRUE* , ensure the corresponding *access_key_n_last_used_date* is less than *45* days ago. + + - When a user having an *access_key_x_active* (where x is 1 or 2) to *TRUE* and corresponding access_key_x_last_used_date is set to *N/A*', *ensure* access_key_x_last_rotated is less than 45 days ago.`, + + rationale: 'Disabling or removing unnecessary credentials will reduce the window of opportunity for credentials associated with a compromised or abandoned account to be used.', + + remediation: `**From Console:** + Perform the following to manage Unused Password (IAM user console access) + + 1. Login to the AWS Management Console: + 2. Click *Services* + 3. Click *IAM* + 4. Click on *Users* + 5. Click on *Security Credentials* + 6. Select user whose *Console last sign-in* is greater than 45 days + 7. Click *Security credentials* + 8. In section *Sign-in credentials*, *Console password* click *Manage* + 9. Under Console Access select *Disable* + 10. Click *Apply* + + Perform the following to deactivate Access Keys: + + 1. Login to the AWS Management Console: + 2. Click *Services* + 3. Click *IAM* + 4. Click on *Users* + 5. Click on *Security Credentials* + 6. Select any access keys that are over 45 days old and that have been used and + - Click on *Make Inactive* + 7. Select any access keys that are over 45 days old and that have not been used and + - Click the X to *Delete*`, + + references: [ + 'CCE-78900-8', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#remove-credentials', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_finding-unused.html', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_admin-change-user.html', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html', + ], + gql: `{ + queryawsIamUser { + id + arn + accountId + __typename + passwordLastUsed + accessKeyData { + lastUsedDate + } + } + }`, + resource: 'queryawsIamUser[*]', + severity: 'medium', + conditions: { + or: [ + { + and: [ + { + path: '@.accessKeyData', + isEmpty: true + }, + { + not: { + path: '@.passwordLastUsed', + notIn: [null, 'N/A', ''] + } + } + ] + }, + { + value: { daysAgo: {}, path: '@.passwordLastUsed' }, + lessThanInclusive: 45, + }, + { + path: '@.accessKeyData', + array_any: { + value: { daysAgo: {}, path: '[*].lastUsedDate' }, + lessThanInclusive: 45, + }, + }, + ], + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.13.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.13.ts new file mode 100644 index 00000000..07671979 --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.13.ts @@ -0,0 +1,92 @@ +export default { + id: 'aws-cis-1.4.0-1.13', + title: 'AWS CIS 1.13 Ensure there is only one active access key available for any single IAM user', + + description: 'Access keys are long-term credentials for an IAM user or the AWS account \'root\' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)', + + audit: `**From Console:** + + 1. Sign in to the AWS Management Console and navigate to IAM dashboard at https://console.aws.amazon.com/iam/. + 2. In the left navigation panel, choose Users. + 3. Click on the IAM user name that you want to examine. + 4. On the IAM user configuration page, select Security Credentials tab. + 5. Under Access Keys section, in the Status column, check the current status for each access key associated with the IAM user. If the selected IAM user has more than one access key activated then the users access configuration does not adhere to security best practices and the risk of accidental exposures increases. + + - Repeat steps no. 3 – 5 for each IAM user in your AWS account. + + **From Command Line:** + + 1. Run list-users command to list all IAM users within your account: + + aws iam list-users --query "Users[*].UserName + + 2. Run list-access-keys command using the IAM user name list to return the current status of each access key associated with the selected IAM user: + + aws iam list-access-keys --user-name + + The command output should expose the metadata ("Username", "AccessKeyId", "Status", "CreateDate") for each access key on that user account. + + 3. Check the Status property value for each key returned to determine each keys current state. If the Status property value for more than one IAM access key is set to Active, the user access configuration does not adhere to this recommendation, refer to the remediation below. + + - Repeat steps no. 2 and 3 for each IAM user in your AWS account." + + The command output should return an array that contains all your IAM user names.`, + + rationale: 'Access keys are long-term credentials for an IAM user or the AWS account \'root\' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API. One of the best ways to protect your account is to not allow users to have multiple access keys.', + + remediation: `**From Console:** + + 1. Sign in to the AWS Management Console and navigate to IAM dashboard at https://console.aws.amazon.com/iam/. + 2. In the left navigation panel, choose Users. + 3. Click on the IAM user name that you want to examine. + 4. On the IAM user configuration page, select Security Credentials tab. + 5. In Access Keys section, choose one access key that is less than 90 days old. This should be the only active key used by this IAM user to access AWS resources programmatically. Test your application(s) to make sure that the chosen access key is working. + 6. In the same Access Keys section, identify your non-operational access keys (other than the chosen one) and deactivate it by clicking the Make Inactive link. + 7. If you receive the Change Key Status confirmation box, click Deactivate to switch off the selected key. + 8. Repeat steps no. 3 – 7 for each IAM user in your AWS account. + + **From Command Line:** + + 1. Using the IAM user and access key information provided in the Audit CLI, choose one access key that is less than 90 days old. This should be the only active key used by this IAM user to access AWS resources programmatically. Test your application(s) to make sure that the chosen access key is working. + 2. Run the update-access-key command below using the IAM user name and the non-operational access key IDs to deactivate the unnecessary key(s). Refer to the Audit section to identify the unnecessary access key ID for the selected IAM user + + **Note** - the command does not return any output: + + aws iam update-access-key --access-key-id --status Inactive --user-name + + 3. To confirm that the selected access key pair has been successfully deactivated run the list-access-keys audit command again for that IAM User: + + aws iam list-access-keys --user-name + + - The command output should expose the metadata for each access key associated with the IAM user. If the non-operational key pair(s) Status is set to Inactive, the key has been successfully deactivated and the IAM user access configuration adheres now to this recommendation. + + 4. Repeat steps no. 1 – 3 for each IAM user in your AWS account.`, + + references: [ + 'https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html', + ], + gql: `{ + queryawsIamUser { + id + arn + accountId + __typename + accessKeyData { + status + } + } + }`, + resource: 'queryawsIamUser[*]', + severity: 'medium', + conditions: { + jq: '.accessKeyData | map(select(.status == "Active")) | { "oneOrLess" : (length <= 1) }', + path: '@', + and: [ + { + path: '@.oneOrLess', + equal: true, + }, + ], + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.14.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.14.ts new file mode 100644 index 00000000..40fd044f --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.14.ts @@ -0,0 +1,116 @@ +// AWS CIS 1.2.0 Rule equivalent 1.4 +export default { + id: 'aws-cis-1.4.0-1.14', + title: 'AWS CIS 1.14 Ensure access keys are rotated every 90 days or less', + + description: '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.', + + audit: `Perform the following to determine if access keys are rotated as prescribed: + + **From Console:** + + 1. Go to Management Console (https://console.aws.amazon.com/iam) + 2. Click on Users + 3. Click setting icon + 4. Select “Console last sign-in” + 5. Click Close + 6. Ensure that “Access key age” is less than 90 days ago. + + **Note:** "None" in the "Access key age" means the user has not used the access key. + + **From Command Line:** + + aws iam generate-credential-report + + aws iam get-credential-report --query 'Content' --output text | base64 -d + + The access_key_1_last_rotated field in this file notes The date and time, in ISO 8601 date-time format, when the user's access key was created or last changed. If the user does not have an active access key, the value in this field is N/A (not applicable).`, + + rationale: `Rotating access keys will reduce the window of opportunity for an access key that is associated with a compromised or terminated account to be used. + + Access keys should be rotated to ensure that data cannot be accessed with an old key which might have been lost, cracked, or stolen.`, + + remediation: `Perform the following to rotate access keys: + + **From Console:** + + 1. Go to Management Console (https://console.aws.amazon.com/iam) + 2. Click on Users + 3. Click on Security Credentials + 4. As an Administrator + - Click on Make Inactive for keys that have not been rotated in 90 Days + 5. As an IAM User + - Click on Make Inactive or Delete for keys which have not been rotated or used in 90 Days + 6. Click on Create Access Key + 7. Update programmatic call with new Access Key credentials + + **From Command Line:** + + 1. While the first access key is still active, create a second access key, which is active by default. Run the following command: + + aws iam create-access-key + + At this point, the user has two active access keys. + + 2. Update all applications and tools to use the new access key. + 3. Determine whether the first access key is still in use by using this command: + + aws iam get-access-key-last-used + + 4. One approach is to wait several days and then check the old access key for any use before proceeding. + + Even if step Step 3 indicates no use of the old key, it is recommended that you do not immediately delete the first access key. Instead, change the state of the first access key to Inactive using this command: + + aws iam update-access-key + + 5. Use only the new access key to confirm that your applications are working. Any applications and tools that still use the original access key will stop working at this point because they no longer have access to AWS resources. If you find such an application or tool, you can switch its state back to Active to reenable the first access key. Then return to step Step 2 and update this application to use the new key. + + 6. After you wait some period of time to ensure that all applications and tools have been updated, you can delete the first access key with this command: + + aws iam delete-access-key`, + + references: [ + 'CCE-78902-4', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_finding-unused.html', + 'https://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html', + ], + gql: `{ + queryawsIamUser { + id + arn + accountId + __typename + accessKeyData { + status + lastRotated + } + } + }`, + resource: 'queryawsIamUser[*]', + severity: 'medium', + conditions: { + or: [ + { + path: '@.accessKeyData', + isEmpty: true + }, + { + path: '@.accessKeyData', + array_any: { + and: [ + { + value: { daysAgo: {}, path: '[*].lastRotated' }, + lessThanInclusive: 90, + }, + { + path: '[*].status', + equal: 'Active', + }, + ], + }, + }, + ], + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.15.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.15.ts new file mode 100644 index 00000000..3405c983 --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.15.ts @@ -0,0 +1,83 @@ +// AWS CIS 1.2.0 Rule equivalent 1.16 +export default { + id: 'aws-cis-1.4.0-1.15', + title: 'AWS CIS 1.15 Ensure IAM Users Receive Permissions Only Through Groups', + + description: `IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. + + Only the third implementation is recommended.`, + + audit: `Perform the following to determine if an inline policy is set or a policy is directly attached to users: + + 1. Run the following to get a list of IAM users: + + aws iam list-users --query 'Users[*].UserName' --output text + + 2. For each user returned, run the following command to determine if any policies are attached to them: + + aws iam list-attached-user-policies --user-name + aws iam list-user-policies --user-name + + 3. If any policies are returned, the user has an inline policy or direct policy attachment.`, + + rationale: 'Assigning IAM policy only through groups unifies permissions management to a single, flexible layer consistent with organizational functional roles. By unifying permissions management, the likelihood of excessive permissions is reduced.', + + remediation: `Perform the following to create an IAM group and assign a policy to it: + + 1. Sign in to the AWS Management Console and open the IAM console at https://console.aws.amazon.com/iam/. + 2. In the navigation pane, click Groups and then click Create New Group . + 3. In the Group Name box, type the name of the group and then click Next Step . + 4. In the list of policies, select the check box for each policy that you want to apply to all members of the group. Then click Next Step . + 5. Click Create Group + + Perform the following to add a user to a given group: + + 1. Sign in to the AWS Management Console and open the IAM console at https://console.aws.amazon.com/iam/. + 2. In the navigation pane, click Groups + 3. Select the group to add a user to + 4. Click Add Users To Group + 5. Select the users to be added to the group + 6. Click Add Users + + Perform the following to remove a direct association between a user and policy: + + 1. Sign in to the AWS Management Console and open the IAM console at https://console.aws.amazon.com/iam/. + 2. In the left navigation pane, click on Users + 3. For each user: + - Select the user + - Click on the Permissions tab + - Expand Permissions policies + - Click X for each policy; then click Detach or Remove (depending on policy type)`, + + references: [ + 'http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html', + 'http://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html', + 'CCE-78912-3', + ], + gql: `{ + queryawsIamUser { + id + arn + accountId + __typename + iamAttachedPolicies { + name + }, + inlinePolicies + } + }`, + resource: 'queryawsIamUser[*]', + severity: 'medium', + conditions: { + and: [ + { + path: '@.iamAttachedPolicies', + isEmpty: true, + }, + { + path: '@.inlinePolicies', + isEmpty: true, + }, + ], + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.16.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.16.ts new file mode 100644 index 00000000..60208fdc --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.16.ts @@ -0,0 +1,102 @@ +// AWS CIS 1.2.0 Rule equivalent 1.22 +export default { + id: 'aws-cis-1.4.0-1.16', + title: 'AWS CIS 1.16 Ensure IAM policies that allow full "*:*" administrative privileges are not attached', + + description: 'IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges.', + + audit: `Perform the following to determine what policies are created: + + **From Command Line:** + + 1. Run the following to get a list of IAM policies: + + aws iam list-policies --only-attached --output text + + 2. For each policy returned, run the following command to determine if any policies is allowing full administrative privileges on the account: + + aws iam get-policy-version --policy-arn --version-id + + 3. In output ensure policy should not have any Statement block with "Effect": "Allow" and Action set to "*" and Resource set to "*"`, + + rationale: `It's more secure to start with a minimum set of permissions and grant additional permissions as necessary, rather than starting with permissions that are too lenient and then trying to tighten them later. + + Providing full administrative privileges instead of restricting to the minimum set of permissions that the user is required to do exposes the resources to potentially unwanted actions. + + IAM policies that have a statement with "Effect": "Allow" with "Action": "*" over "Resource": "*" should be removed.`, + + remediation: `**From Console:** + Perform the following to detach the policy that has full administrative privileges: + + 1. Sign in to the AWS Management Console and open the IAM console at https://console.aws.amazon.com/iam/. + 2. In the navigation pane, click Policies and then search for the policy name found in the audit step. + 3. Select the policy that needs to be deleted. + 4. In the policy action menu, select first Detach + 5. Select all Users, Groups, Roles that have this policy attached + 6. Click Detach Policy + 7. In the policy action menu, select Detach + + **From Command Line:** + Perform the following to detach the policy that has full administrative privileges as found in the audit step: + + 1. Lists all IAM users, groups, and roles that the specified managed policy is attached to. + + aws iam list-entities-for-policy --policy-arn + + 2. Detach the policy from all IAM Users: + + aws iam detach-user-policy --user-name --policy-arn + + 3. Detach the policy from all IAM Groups: + + aws iam detach-group-policy --group-name --policy-arn + + 4. Detach the policy from all IAM Roles: + + aws iam detach-role-policy --role-name --policy-arn `, + + references: [ + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html', + 'CCE-78912-3', + 'https://docs.aws.amazon.com/cli/latest/reference/iam/index.html#cli-aws-iam', + ], + gql: `{ + queryawsIamPolicy { + id + arn + accountId + __typename + policyContent { + statement { + effect + action + resource + } + } + } + }`, + resource: 'queryawsIamPolicy[*]', + severity: 'high', + conditions: { + not: { + path: '@.policyContent.statement', + array_any: { + and: [ + { + path: '[*].effect', + equal: 'Allow', + }, + { + path: '[*].action', + contains: '*', + }, + { + path: '[*].resource', + contains: '*', + }, + ], + }, + }, + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.17.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.17.ts new file mode 100644 index 00000000..363c853d --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.17.ts @@ -0,0 +1,105 @@ +// AWS CIS 1.2.0 Rule equivalent 1.20 +export default { + id: 'aws-cis-1.4.0-1.17', + title: 'AWS CIS 1.17 Ensure a support role has been created to manage incidents with AWS Support', + + description: 'AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support.', + + audit: `**From Command Line:** + + 1. List IAM policies, filter for the 'AWSSupportAccess' managed policy, and note the "Arn" element value: + + aws iam list-policies --query "Policies[?PolicyName == 'AWSSupportAccess']" + + 2. Check if the 'AWSSupportAccess' policy is attached to any role: + + aws iam list-entities-for-policy --policy-arn arn:aws:iam::aws:policy/AWSSupportAccess + + 3. In Output, Ensure PolicyRoles does not return empty. 'Example: Example: PolicyRoles: [ ]' + + If it returns empty refer to the remediation below.`, + + rationale: 'By implementing least privilege for access control, an IAM Role will require an appropriate IAM Policy to allow Support Center Access in order to manage Incidents with AWS Support.', + + remediation: `**From Command Line:** + + 1. Create an IAM role for managing incidents with AWS: + + - Create a trust relationship policy document that allows to manage AWS incidents, and save it locally as /tmp/TrustPolicy.json: + + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "AWS": "" + }, + "Action": "sts:AssumeRole" + } + ] + } + + 2. Create the IAM role using the above trust policy: + + aws iam create-role --role-name --assume-role-policy-document file:///tmp/TrustPolicy.json + + 3. Attach 'AWSSupportAccess' managed policy to the created IAM role: + + aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AWSSupportAccess --role-name `, + + references: [ + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html', + 'https://aws.amazon.com/premiumsupport/pricing/', + 'https://docs.aws.amazon.com/cli/latest/reference/iam/list-policies.html', + 'https://docs.aws.amazon.com/cli/latest/reference/iam/attach-role-policy.html', + 'https://docs.aws.amazon.com/cli/latest/reference/iam/list-entities-for-policy.html', + ], + gql: `{ + queryawsAccount { + id + __typename + iamPolicies { + name + iamUsers { + arn + } + iamGroups { + arn + } + iamRoles { + arn + } + } + } + }`, + resource: 'queryawsAccount[*]', + severity: 'medium', + conditions: { + path: '@.iamPolicies', + array_any: { + and: [ + { + path: '[*].name', + equal: 'AWSSupportAccess', + }, + { + or: [ + { + path: '[*].iamUsers', + isEmpty: false, + }, + { + path: '[*].iamGroups', + isEmpty: false, + }, + { + path: '[*].iamRoles', + isEmpty: false, + }, + ], + }, + ], + }, + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.19.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.19.ts new file mode 100644 index 00000000..c88c0435 --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.19.ts @@ -0,0 +1,68 @@ +export default { + id: 'aws-cis-1.4.0-1.19', + title: 'AWS CIS 1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed', + + description: 'To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.', + + audit: `**From Console:** + Getting the certificates expiration information via AWS Management Console is not currently supported. + To request information about the SSL/TLS certificates stored in IAM via the AWS API use the Command Line Interface (CLI). + + **From Command Line:** + Run list-server-certificates command to list all the IAM-stored server certificates: + + aws iam list-server-certificates + + The command output should return an array that contains all the SSL/TLS certificates currently stored in IAM and their metadata (name, ID, expiration date, etc): + + { + "ServerCertificateMetadataList": [ + { + "ServerCertificateId": "EHDGFRW7EJFYTE88D", + "ServerCertificateName": "MyServerCertificate", + "Expiration": "2018-07-10T23:59:59Z", + "Path": "/", + "Arn": "arn:aws:iam::012345678910:server-certificate/MySSLCertificate", + "UploadDate": "2018-06-10T11:56:08Z" + } + ] + } + + Verify the ServerCertificateName and Expiration parameter value (expiration date) for each SSL/TLS certificate returned by the list-server-certificates command and determine if there are any expired server certificates currently stored in AWS IAM. If so, use the AWS API to remove them. + If this command returns: + + { { "ServerCertificateMetadataList": [] } + + This means that there are no expired certificates, It DOES NOT mean that no certificates exist.`, + + rationale: 'Removing expired SSL/TLS certificates eliminates the risk that an invalid certificate will be deployed accidentally to a resource such as AWS Elastic Load Balancer (ELB), which can damage the credibility of the application/website behind the ELB. As a best practice, it is recommended to delete expired certificates.', + + remediation: `**From Console:** + Removing expired certificates via AWS Management Console is not currently supported. To delete SSL/TLS certificates stored in IAM via the AWS API use the Command Line Interface (CLI). + **From Command Line:** + To delete Expired Certificate run following command by replacing with the name of the certificate to delete: + + aws iam delete-server-certificate --server-certificate-name + + When the preceding command is successful, it does not return any output.`, + + references: [ + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_server-certs.html', + 'https://docs.aws.amazon.com/cli/latest/reference/iam/delete-server-certificate.html', + ], + gql: `{ + queryawsIamServerCertificate { + id + arn + accountId + __typename + expiration + } + }`, + resource: 'queryawsIamServerCertificate[*]', + severity: 'high', + conditions: { + value: { daysDiff: {}, path: '@.expiration' }, + greaterThanInclusive: 1, + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.21.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.21.ts new file mode 100644 index 00000000..e5065b20 --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.21.ts @@ -0,0 +1,43 @@ +export default { + id: 'aws-cis-1.4.0-1.21', + title: 'AWS CIS 1.21 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments (Manual)', + + description: 'In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.', + + audit: `For multi-account AWS environments with an external identity provider... + + 1. Determine the master account for identity federation or IAM user management + 2. Login to that account through the AWS Management Console + 3. Click Services + 4. Click IAM + 5. Click Identity providers + 6. Verify the configuration + + Then..., determine all accounts that should not have local users present. For each account... + + 1. Determine all accounts that should not have local users present + 2. Log into the AWS Management Console + 3. Switch role into each identified account + 4. Click *Services* + 5. Click *IAM* + 6. Click *Users* + 7. Confirm that no IAM users representing individuals are present + + For multi-account AWS environments implementing AWS Organizations without an external identity provider... + + 1. Determine all accounts that should not have local users present + 2. Log into the AWS Management Console + 3. Switch role into each identified account + 4. Click *Services* + 5. Click *IAM* + 6. Click *Users* + 7. Confirm that no IAM users representing individuals are present`, + + rationale: 'Centralizing IAM user management to a single identity store reduces complexity and thus the likelihood of access management errors.', + + remediation: 'The remediation procedure will vary based on the individual organization\'s implementation of identity federation and/or AWS Organizations with the acceptance criteria that no non-service IAM users, and non-root accounts, are present outside the account providing centralized IAM user management.', + + references: [], + + severity: 'medium', +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.4.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.4.ts new file mode 100644 index 00000000..da44a6d4 --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.4.ts @@ -0,0 +1,62 @@ +// AWS CIS 1.2.0 Rule equivalent 1.12 +export default { + id: 'aws-cis-1.4.0-1.4', + title: 'AWS CIS 1.4 Ensure no \'root\' user account access key exists', + + description: 'The \'root\' user 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\' user account be removed.', + + audit: `Perform the following to determine if the 'root' user account has access keys: + + **From Console:** + + 1. Login to the AWS Management Console + 2. Click *Services* + 3. Click *IAM* + 4. Click on *Credential Report* + 5. This will download an *.xls* file which contains credential usage for all IAM users within an AWS Account - open this file + 6. For the ** user, ensure the *access_key_1_active* and *access_key_2_active* fields are set to *FALSE* . + + **From Command Line:** + Run the following command: + + aws iam get-account-summary | grep "AccountAccessKeysPresent" + + If no 'root' access keys exist the output will show "AccountAccessKeysPresent": 0,. If the output shows a "1" than 'root' keys exist, refer to the remediation procedure below.`, + + rationale: 'Removing access keys associated with the \'root\' user account limits vectors by which the account can be compromised. Additionally, removing the \'root\' access keys encourages the creation and use of role based accounts that are least privileged.', + + remediation: `Perform the following to delete or disable active 'root' user access keys + + **From Console:** + + 1. Sign in to the AWS Management Console as 'root' and open the IAM console at https://console.aws.amazon.com/iam/. + 2. Click on at the top right and select *My Security Credentials* from the drop down list + 3. On the pop out screen Click on *Continue to Security Credentials* + 4. Click on *Access Keys* *(Access Key ID and Secret Access Key)* + 5. Under the *Status* column if there are any Keys which are Active + - Click on *Make Inactive* - (Temporarily disable Key - may be needed again) + - Click *Delete* - (Deleted keys cannot be recovered)`, + + references: [ + 'http://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html', + 'http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html', + 'http://docs.aws.amazon.com/IAM/latest/APIReference/API_GetAccountSummary.html', + 'CCE-78910-7', + 'https://aws.amazon.com/blogs/security/an-easier-way-to-determine-the-presence-of-aws-account-access-keys/', + ], + gql: `{ + queryawsIamUser(filter: { name: { eq: "root" } }) { + id + arn + accountId + __typename + accessKeysActive + } + }`, + resource: 'queryawsIamUser[*]', + severity: 'high', + conditions: { + path: '@.accessKeysActive', + equal: false, + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.5.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.5.ts new file mode 100644 index 00000000..f9bc5ad7 --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.5.ts @@ -0,0 +1,60 @@ +// AWS CIS 1.2.0 Rule equivalent 1.13 +export default { + id: 'aws-cis-1.4.0-1.5', + title: 'AWS CIS 1.5 Ensure MFA is enabled for the \'root\' user account', + + description: `The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device. + + **Note:** 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, device trade-in or if the individual owning the device is no longer employed at the company.`, + + audit: `Perform the following to determine if the 'root' user account has MFA setup: + + **From Command Line:** + + 1. Run the following command: + + aws iam get-account-summary | grep "AccountMFAEnabled" + + 2. Ensure the AccountMFAEnabled property is set to 1`, + + rationale: 'Enabling MFA provides increased security for console access as it requires the authenticating principal to possess a device that emits a time-sensitive key and have knowledge of a credential.', + + remediation: `Perform the following to establish MFA for the 'root' user account: + + 1. Sign in to the AWS Management Console and open the IAM console at https://console.aws.amazon.com/iam/. + + Note: to manage MFA devices for the 'root' AWS account, you must use your 'root' account credentials to sign in to AWS. You cannot manage MFA devices for the 'root' account using other credentials. + + 2. Choose *Dashboard* , and under *Security Status* , expand *Activate MFA* on your root account. + 3. Choose *Activate MFA* + 4. In the wizard, choose *A virtual MFA* device and then choose *Next Step*. + 5. IAM generates and displays configuration information for the virtual MFA device, including a QR code graphic. The graphic is a representation of the 'secret configuration key' that is available for manual entry on devices that do not support QR codes. + 6. Open your virtual MFA application. (For a list of apps that you can use for hosting virtual MFA devices, see [Virtual MFA Applications](https://aws.amazon.com/iam/features/mfa/?audit=2019q1#Virtual_MFA_Applications).) If the virtual MFA application supports multiple accounts (multiple virtual MFA devices), choose the option to create a new account (a new virtual MFA device). + 7. Determine whether the MFA app supports QR codes, and then do one of the following: + - Use the app to scan the QR code. For example, you might choose the camera icon or choose an option similar to Scan code, and then use the device's camera to scan the code. + - In the Manage MFA Device wizard, choose Show secret key for manual configuration, and then type the secret configuration key into your MFA application. + + When you are finished, the virtual MFA device starts generating one-time passwords. In the Manage MFA Device wizard, in the Authentication Code 1 box, type the one-time password that currently appears in the virtual MFA device. Wait up to 30 seconds for the device to generate a new one-time password. Then type the second one-time password into the Authentication Code 2 box. Choose Active Virtual MFA.`, + + references: [ + 'CCE-78911-5', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#id_root-user_manage_mfa', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html#enable-virt-mfa-for-root', + ], + gql: `{ + queryawsIamUser(filter: { name: { eq: "root" } }) { + id + arn + accountId + __typename + name + mfaActive + } + }`, + resource: 'queryawsIamUser[*]', + severity: 'high', + conditions: { + path: '@.mfaActive', + equal: true, + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.6.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.6.ts new file mode 100644 index 00000000..b9061a4a --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.6.ts @@ -0,0 +1,79 @@ +// AWS CIS 1.2.0 Rule equivalent 1.14 +export default { + id: 'aws-cis-1.4.0-1.6', + title: 'AWS CIS 1.6 Ensure hardware MFA is enabled for the \'root\' user account', + + description: 'The \'root\' user 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\' user account be protected with a hardware MFA.', + + audit: `Perform the following to determine if the 'root' user account has a hardware MFA setup: + + 1. Run the following command to determine if the 'root' account has MFA setup: + + aws iam get-account-summary | grep "AccountMFAEnabled" + + The *AccountMFAEnabled* property is set to 1 will ensure that the 'root' user account has MFA (Virtual or Hardware) Enabled. + If *AccountMFAEnabled* property is set to *0* the account is not compliant with this recommendation. + + 2. If *AccountMFAEnabled* property is set to *1*, determine 'root' account has Hardware MFA enabled. + Run the following command to list all virtual MFA devices: + + aws iam list-virtual-mfa-devices + + If the output contains one MFA with the following Serial Number, it means the MFA is virtual, not hardware and the account is not compliant with this recommendation: *"SerialNumber": "arn:aws:iam::__:mfa/root-account-mfa-device"*`, + + rationale: `A hardware MFA has a smaller attack surface than a virtual MFA. For example, a hardware MFA does not suffer the attack surface introduced by the mobile smartphone on which a virtual MFA resides. + + **Note:** Using hardware MFA for many, many AWS accounts may create a logistical device management issue. If this is the case, consider implementing this Level 2 recommendation selectively to the highest security AWS accounts and the Level 1 recommendation applied to the remaining accounts.`, + + remediation: `Perform the following to establish a hardware MFA for the 'root' user account: + + 1. Sign in to the AWS Management Console and open the IAM console at https://console.aws.amazon.com/iam/. Note: to manage MFA devices for the AWS 'root' user account, you must use your 'root' account credentials to sign in to AWS. You cannot manage MFA devices for the 'root' account using other credentials. + 2. Choose *Dashboard* , and under *Security Status* , expand *Activate MFA* on your root account. + 3. Choose *Activate MFA* + 4. In the wizard, choose *A hardware MFA* device and then choose *Next Step*. + 5. In the *Serial Number* box, enter the serial number that is found on the back of the MFA device. + 6. In the *Authentication Code 1* box, enter the six-digit number displayed by the MFA device. You might need to press the button on the front of the device to display the number. + 7. Wait 30 seconds while the device refreshes the code, and then enter the next six-digit number into the *Authentication Code 2* box. You might need to press the button on the front of the device again to display the second number. + 8. Choose *Next Step*. The MFA device is now associated with the AWS account. The next time you use your AWS account credentials to sign in, you must type a code from the hardware MFA device. + + Remediation for this recommendation is not available through AWS`, + + references: [ + 'CCE-78911-5', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_physical.html#enable-hw-mfa-for-root', + ], + gql: `{ + queryawsIamUser(filter: { name: { eq: "root" } }) { + id + arn + accountId + __typename + name + mfaActive + virtualMfaDevices { + serialNumber + } + } + }`, + resource: 'queryawsIamUser[*]', + severity: 'high', + conditions: { + and: [ + { + path: '@.mfaActive', + equal: true, + }, + { + jq: '[select("arn:aws:iam::" + .accountId + ":mfa/root-account-mfa-device" == .virtualMfaDevices[].serialNumber)] | { "match" : (length > 0) }', + path: '@', + and: [ + { + path: '@.match', + notEqual: true, + }, + ], + }, + ], + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.7.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.7.ts new file mode 100644 index 00000000..2fe85157 --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.7.ts @@ -0,0 +1,70 @@ +// AWS CIS 1.2.0 Rule equivalent 1.1 +export default { + id: 'aws-cis-1.4.0-1.7', + title: 'AWS CIS 1.7 Eliminate use of the \'root\' user for administrative and daily tasks', + + description: 'With the creation of an AWS account, a \'root user\' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.', + + audit: `**From Console:** + + 1. Login to the AWS Management Console at https://console.aws.amazon.com/iam/ + 2. In the left pane, click *Credential Report* + 3. Click on *Download Report* + 4. Open of Save the file locally + 5. Locate the ** under the user column + 6. Review *password_last_used*, *access_key_1_last_used_date*, *access_key_2_last_used_date* to determine when the 'root user' was last used. + + **From Command Line:** + Run the following CLI commands to provide a credential report for determining the last time the 'root user' was used: + + aws iam generate-credential-report + + aws iam get-credential-report --query 'Content' --output text | base64 -d | cut -d, -f1,5,11,16 | grep -B1 '' + + Review *password_last_used*, *access_key_1_last_used_date*, *access_key_2_last_used_date* to determine when the root user was last used. + + **Note:** There are a few conditions under which the use of the 'root' user account is required. Please see the reference links for all of the tasks that require use of the 'root' user.`, + + rationale: 'The \'root user\' has unrestricted access to and control over all account resources. Use of it is inconsistent with the principles of least privilege and separation of duties, and can lead to unnecessary harm due to error or account compromise.', + + remediation: `Remediation: + + If you find that the 'root' user account is being used for daily activity to include administrative tasks that do not require the 'root' user: + + 1. Change the 'root' user password. + 2. Deactivate or delete any access keys associate with the 'root' user. + + **Remember, anyone who has 'root' user credentials for your AWS account has unrestricted access to and control of all the resources in your account, including billing information.`, + + references: [ + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html', + 'https://docs.aws.amazon.com/general/latest/gr/aws_tasks-that-require-root.html', + ], + gql: `{ + queryawsIamUser(filter: { name: { eq: "root" } }) { + id + arn + accountId + __typename + passwordLastUsed + passwordEnabled + } + }`, + resource: 'queryawsIamUser[*]', + severity: 'high', + conditions: { + not: { + and: [ + { + path: '@.passwordEnabled', + equal: true, + }, + { + value: { daysAgo: {}, path: '@.passwordLastUsed' }, + lessThanInclusive: 30, + }, + ], + }, + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.8.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.8.ts new file mode 100644 index 00000000..3358e440 --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.8.ts @@ -0,0 +1,62 @@ +// AWS CIS 1.2.0 Rule equivalent 1.9 +export default { + id: 'aws-cis-1.4.0-1.8', + title: 'AWS CIS 1.8 Ensure IAM password policy requires minimum length of 14 or greater', + + description: `Password policies are, in part, used to enforce password complexity requirements. IAM + password policies can be used to ensure password are at least a given length. It is + recommended that the password policy require a minimum password length 14.`, + + audit: `Perform the following to ensure the password policy is configured as prescribed: + + **From Console:** + + 1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) + 2. Go to IAM Service on the AWS Console + 3. Click on Account Settings on the Left Pane + 4. Ensure "Minimum password length" is set to 14 or greater. + + **From Command Line:** + + aws iam get-account-password-policy + + Ensure the output of the above command includes "MinimumPasswordLength": 14 (or higher)`, + + rationale: 'Setting a password complexity policy increases account resiliency against brute force login attempts.', + + remediation: `Perform the following to set the password policy as prescribed: + + **From Console:** + + 1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) + 2. Go to IAM Service on the AWS Console + 3. Click on Account Settings on the Left Pane + 4. Set "Minimum password length" to 14 or greater. + 5. Click "Apply password policy" + + **From Command Line:** + + aws iam update-account-password-policy --minimum-password-length 14 + + Note: All commands starting with "aws iam update-account-password-policy" can be combined into a single command.`, + + references: [ + 'CCE-78907-3', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy', + ], + gql: `{ + queryawsIamPasswordPolicy { + id + accountId + __typename + minimumPasswordLength + } + }`, + resource: 'queryawsIamPasswordPolicy[*]', + severity: 'medium', + conditions: { + path: '@.minimumPasswordLength', + greaterThanInclusive: 14, + }, +} diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.9.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.9.ts new file mode 100644 index 00000000..d4de340c --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.9.ts @@ -0,0 +1,61 @@ +// AWS CIS 1.2.0 Rule equivalent 1.10 +export default { + id: 'aws-cis-1.4.0-1.9', + title: 'AWS CIS 1.9 Ensure IAM password policy prevents password reuse', + description: `IAM password policies can prevent the reuse of a given password by the same user. It is + recommended that the password policy prevent the reuse of passwords.`, + + audit: `Perform the following to ensure the password policy is configured as prescribed: + + **From Console:** + + 1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) + 2. Go to IAM Service on the AWS Console + 3. Click on Account Settings on the Left Pane + 4. Ensure "Prevent password reuse" is checked + 5. Ensure "Number of passwords to remember" is set to 24 + + **From Command Line:** + + aws iam get-account-password-policy + + Ensure the output of the above command includes "PasswordReusePrevention": 24`, + + rationale: 'Preventing password reuse increases account resiliency against brute force login attempts.', + + remediation: `Perform the following to set the password policy as prescribed: + + **From Console:** + + 1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) + 2. Go to IAM Service on the AWS Console + 3. Click on Account Settings on the Left Pane + 4. Check "Prevent password reuse" + 5. Set "Number of passwords to remember" is set to 24 + + **From Command Line:** + + aws iam update-account-password-policy --password-reuse-prevention 24 + + Note: All commands starting with "aws iam update-account-password-policy" can be combined into a single command.`, + + references: [ + 'CCE-78908-1', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy', + ], + gql: `{ + queryawsIamPasswordPolicy { + id + accountId + __typename + passwordReusePrevention + } + }`, + resource: 'queryawsIamPasswordPolicy[*]', + severity: 'high', + conditions: { + path: '@.passwordReusePrevention', + greaterThanInclusive: 24, + }, +} diff --git a/src/aws/cis-1.4.0/rules/index.ts b/src/aws/cis-1.4.0/rules/index.ts index c7468a33..aba727df 100644 --- a/src/aws/cis-1.4.0/rules/index.ts +++ b/src/aws/cis-1.4.0/rules/index.ts @@ -1,4 +1,34 @@ +import Aws_CIS_140_14 from './aws-cis-1.4.0-1.4' +import Aws_CIS_140_15 from './aws-cis-1.4.0-1.5' +import Aws_CIS_140_16 from './aws-cis-1.4.0-1.6' +import Aws_CIS_140_17 from './aws-cis-1.4.0-1.7' +import Aws_CIS_140_18 from './aws-cis-1.4.0-1.8' +import Aws_CIS_140_19 from './aws-cis-1.4.0-1.9' +import Aws_CIS_140_110 from './aws-cis-1.4.0-1.10' +import Aws_CIS_140_112 from './aws-cis-1.4.0-1.12' +import Aws_CIS_140_113 from './aws-cis-1.4.0-1.13' +import Aws_CIS_140_114 from './aws-cis-1.4.0-1.14' +import Aws_CIS_140_115 from './aws-cis-1.4.0-1.15' +import Aws_CIS_140_116 from './aws-cis-1.4.0-1.16' +import Aws_CIS_140_117 from './aws-cis-1.4.0-1.17' +import Aws_CIS_140_119 from './aws-cis-1.4.0-1.19' +import Aws_CIS_140_121 from './aws-cis-1.4.0-1.21' + export default [ - // TODO: Add rules to export + Aws_CIS_140_14, + Aws_CIS_140_15, + Aws_CIS_140_16, + Aws_CIS_140_17, + Aws_CIS_140_18, + Aws_CIS_140_19, + Aws_CIS_140_110, + Aws_CIS_140_112, + Aws_CIS_140_113, + Aws_CIS_140_114, + Aws_CIS_140_115, + Aws_CIS_140_116, + Aws_CIS_140_117, + Aws_CIS_140_119, + Aws_CIS_140_121, ] diff --git a/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts b/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts new file mode 100644 index 00000000..d1c73610 --- /dev/null +++ b/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts @@ -0,0 +1,851 @@ +import CloudGraph, { Rule, Result, Engine } from '@cloudgraph/sdk' +import cuid from 'cuid' + +import Aws_CIS_140_14 from '../rules/aws-cis-1.4.0-1.4' +import Aws_CIS_140_15 from '../rules/aws-cis-1.4.0-1.5' +import Aws_CIS_140_16 from '../rules/aws-cis-1.4.0-1.6' +import Aws_CIS_140_17 from '../rules/aws-cis-1.4.0-1.7' +import Aws_CIS_140_18 from '../rules/aws-cis-1.4.0-1.8' +import Aws_CIS_140_19 from '../rules/aws-cis-1.4.0-1.9' +import Aws_CIS_140_110 from '../rules/aws-cis-1.4.0-1.10' +import Aws_CIS_140_112 from '../rules/aws-cis-1.4.0-1.12' +import Aws_CIS_140_113 from '../rules/aws-cis-1.4.0-1.13' +import Aws_CIS_140_114 from '../rules/aws-cis-1.4.0-1.14' +import Aws_CIS_140_115 from '../rules/aws-cis-1.4.0-1.15' +import Aws_CIS_140_116 from '../rules/aws-cis-1.4.0-1.16' +import Aws_CIS_140_117 from '../rules/aws-cis-1.4.0-1.17' +import Aws_CIS_140_119 from '../rules/aws-cis-1.4.0-1.19' + +export interface VirtualMfaDevice { + serialNumber: string +} + +export interface AccessKeyData { + lastUsedDate?: string + status?: string + lastRotated?: string +} + +export interface IamAttachedPolicy { + arn?: string + name?: string +} + +export interface Statement { + effect?: string + action?: string[] + resource?: string[] +} + +export interface AssumeRolePolicy { + statement: Statement[] +} + +export interface PolicyContent { + statement: Statement[] +} + +export interface QueryawsIamPolicy { + id: string + policyContent: PolicyContent +} + +export interface QueryawsIamUser { + id: string + name?: string + accessKeysActive?: boolean + mfaActive?: boolean + accountId?:string + virtualMfaDevices?: VirtualMfaDevice[] + passwordEnabled?: boolean + passwordLastUsed?: string + accessKeyData?: AccessKeyData[] + iamAttachedPolicies?: IamAttachedPolicy[] + inlinePolicies?: string[] +} + +export interface QueryawsIamPasswordPolicy { + id: string + minimumPasswordLength?: number + requireNumbers?: boolean + passwordReusePrevention?: number + requireLowercaseCharacters?: boolean + requireSymbols?: boolean + requireUppercaseCharacters?: boolean + expirePasswords?: boolean + maxPasswordAge?: number +} + +export interface iamRole { + arn: string +} + +export interface iamGroup { + arn: string +} + +export interface IamUser { + arn: string +} + +export interface IamPolicy { + name: string + iamUsers: IamUser[] + iamGroups: iamGroup[] + iamRoles: iamRole[] +} + +export interface QueryawsIamServerCertificate { + id: string + expiration: string +} + +export interface QueryawsAccount { + id: string + iamPolicies: IamPolicy[] +} + +export interface CIS1xQueryResponse { + queryawsIamUser?: QueryawsIamUser[] + queryawsIamPasswordPolicy?: QueryawsIamPasswordPolicy[] + queryawsIamPolicy?: QueryawsIamPolicy[] + queryawsAccount?: QueryawsAccount[] + queryawsIamServerCertificate?: QueryawsIamServerCertificate[] +} + +describe('CIS Amazon Web Services Foundations: 1.4.0', () => { + let rulesEngine: Engine + beforeAll(() => { + rulesEngine = new CloudGraph.RulesEngine({ + providerName: 'aws', + entityName: 'CIS', + }) + }) + + describe('AWS CIS 1.4 Ensure no root user account access key exists', () => { + const getTestRuleFixture = ( + accessKeysActive: boolean + ): CIS1xQueryResponse => { + return { + queryawsIamUser: [ + { + id: cuid(), + accessKeysActive, + }, + ] + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_14 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when a root account does not have any access key active', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(false) + await testRule(data, Result.PASS) + }) + + test('Security Issue when a root account has at least one access key active', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(true) + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 1.5 Ensure MFA is enabled for the root user account', () => { + const getTestRuleFixture = ( + mfaActive: boolean + ): CIS1xQueryResponse => { + return { + queryawsIamUser: [ + { + id: cuid(), + name: 'root', + mfaActive, + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_15 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when a root account has a mfa device active', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(true) + await testRule(data, Result.PASS) + }) + + test('Security Issue when a root account has not a mfa device active', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(false) + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 1.6 Ensure hardware MFA is enabled for the root user account', () => { + const getTestRuleFixture = ( + mfaActive: boolean + ): CIS1xQueryResponse => { + return { + queryawsIamUser: [ + { + id: cuid(), + name: 'root', + mfaActive, + accountId: '123456', + virtualMfaDevices: [ + { + serialNumber: 'arn:aws:iam::123456:mfa/some-account-mfa-device', + }, + ], + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_16 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when a root account has a mfa hardware device active', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(true) + await testRule(data, Result.PASS) + }) + + test('Security Issue when a root account has a mfa hardware device deactivate', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(false) + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 1.6 Eliminate use of the root user for administrative and daily tasks', () => { + const getTestRuleFixture = ( + mfaActive: boolean + ): CIS1xQueryResponse => { + return { + queryawsIamUser: [ + { + id: cuid(), + name: 'root', + mfaActive, + accountId: '123456', + virtualMfaDevices: [ + { + serialNumber: 'arn:aws:iam::123456:mfa/some-account-mfa-device', + }, + ], + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_16 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when a root account has a mfa hardware device active', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(true) + await testRule(data, Result.PASS) + }) + + test('Security Issue when a root account has a mfa hardware device deactivate', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(false) + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 1.7 Eliminate use of the root user for administrative and daily tasks', () => { + const getTestRuleFixture = ( + passwordLastUsed: string + ): CIS1xQueryResponse => { + return { + queryawsIamUser: [ + { + id: cuid(), + passwordEnabled: true, + passwordLastUsed, + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_17 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when when a root account does not uses his password in the last 30 days', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('2021-04-08T17:20:19.000Z') + await testRule(data, Result.PASS) + }) + + test('Security Issue when a root account uses his password in the last 30 days', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(new Date().toISOString()) + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 1.8 Ensure IAM password policy requires minimum length of 14 or greater', () => { + const getTestRuleFixture = ( + minimumPasswordLength: number + ): CIS1xQueryResponse => { + return { + queryawsIamPasswordPolicy: [ + { + id: cuid(), + minimumPasswordLength, + }, + ] + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_18 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when password policy minimum length is greater than or equal to 14', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(14) + await testRule(data, Result.PASS) + }) + + test('Security Issue when password policy minimum length is less than 14', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(13) + await testRule(data, Result.FAIL) + }) + + }) + + describe('AWS CIS 1.9 Ensure IAM password policy prevents password reuse', () => { + const getTestRuleFixture = ( + passwordReusePrevention: number + ): CIS1xQueryResponse => { + return { + queryawsIamPasswordPolicy: [ + { + id: cuid(), + passwordReusePrevention, + }, + ] + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_19 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue if the number of previous passwords is more than 24', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(25) + await testRule(data, Result.PASS) + }) + + test('Security Issue if the number of previous passwords is less than 24', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(23) + await testRule(data, Result.FAIL) + }) + + }) + + describe('AWS CIS 1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password', () => { + const getTestRuleFixture = ( + passwordEnabled: boolean, + mfaActive: boolean + ): CIS1xQueryResponse => { + return { + queryawsIamUser: [ + { + id: cuid(), + passwordEnabled, + mfaActive, + }, + ] + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_110 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when a user has no active password', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(false, true) + await testRule(data, Result.PASS) + }) + + test('No Security Issue when a user has an active password with an mfa device register', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(true, true) + await testRule(data, Result.PASS) + }) + + test('Security Issue when a user has an active password without an mfa device register', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(true, false) + await testRule(data, Result.FAIL) + }) + + }) + + describe('AWS CIS 1.12 Ensure credentials unused for 45 days or greater are disabled', () => { + const getTestRuleFixture = ( + passwordLastUsed: string, + lastUsedDate: string + ): CIS1xQueryResponse => { + return { + queryawsIamUser: [ + { + id: cuid(), + passwordLastUsed, + accessKeyData: [ + { + lastUsedDate, + } + ], + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_112 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when there are an access key unused for less than 90 days', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('', new Date().toISOString()) + await testRule(data, Result.PASS) + }) + + test('No Security Issue when no password last used AND no access key data', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('', '') + const queryawsIamUser = data.queryawsIamUser?.[0] as QueryawsIamUser + queryawsIamUser.accessKeyData = [] + await testRule(data, Result.PASS) + }) + + test('Security Issue when there are an access key unused for more than 90 days', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('', '2021-05-27T20:29:00.000Z') + await testRule(data, Result.FAIL) + }) + + test('Security Issue when there are a passwoord unused for more than 90 days', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('2021-05-27T20:29:00.000Z', '') + const queryawsIamUser = data.queryawsIamUser?.[0] as QueryawsIamUser + queryawsIamUser.accessKeyData = [] + await testRule(data, Result.FAIL) + }) + + }) + + describe('AWS CIS 1.13 Ensure there is only one active access key available for any single IAM user', () => { + const getTestRuleFixture = ( + status: string + ): CIS1xQueryResponse => { + return { + queryawsIamUser: [ + { + id: cuid(), + accessKeyData: [ + { + status, + }, + { + status: 'Active', + } + ], + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_113 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when there is only one active access key available for any single IAM user', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('Inactive') + await testRule(data, Result.PASS) + }) + + test('Security Issue when there are more than one active access key available for any single IAM user', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('Active') + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 1.14 Ensure access keys are rotated every 90 days or less', () => { + const getTestRuleFixture = ( + status: string, + lastRotated: string + ): CIS1xQueryResponse => { + return { + queryawsIamUser: [ + { + id: cuid(), + accessKeyData: [ + { + status, + lastRotated, + }, + { + status: 'Active', + lastRotated: '2021-08-27T15:00:44.000Z', + } + ], + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_114 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when users have an active access key created for less than 90 days', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('Active', new Date().toISOString()) + await testRule(data, Result.PASS) + }) + + test('Security Issue when users have an active access key created for more than 90 days', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('Active', '2021-09-23T15:56:01.000Z') + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 1.15 Ensure IAM Users Receive Permissions Only Through Groups', () => { + const getTestRuleFixture = ( + iamAttachedPolicies: IamAttachedPolicy[], + inlinePolicies: string[] + ): CIS1xQueryResponse => { + return { + queryawsIamUser: [ + { + id: cuid(), + iamAttachedPolicies, + inlinePolicies, + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_115 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when users does not have attached policies directly', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture([],[]) + await testRule(data, Result.PASS) + }) + + test('Security Issue when users have attached policies directly', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture([{ arn: cuid() }], ['inline_test']) + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 1.16 Ensure IAM policies that allow full "*:*" administrative privileges are not attached', () => { + const getTestRuleFixture = ( + effect: string, + action: string[], + resource: string[] + ): CIS1xQueryResponse => { + return { + queryawsIamPolicy: [ + { + id: cuid(), + policyContent: { + statement: [ + { + effect, + action, + resource + } + ] + } + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_116 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when IAM policies not allow full "*:*" administrative privileges', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('Allow', [ + 'secretsmanager:DeleteSecret', + 'secretsmanager:GetSecretValue', + 'secretsmanager:UpdateSecret', + ], ['arn:aws:secretsmanager:*:*:secret:A4B*']) + await testRule(data, Result.PASS) + }) + + test('No Security Issue when IAM policies that have a statement with "Effect": "Allow" with "Action": "*" over restricted "Resource"', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('Allow', ['*'], ['arn:aws:secretsmanager:*:*:secret:A4B*']) + await testRule(data, Result.PASS) + }) + + test('No Security Issue when IAM policies that have a statement with "Effect": "Allow" with restricted "Action" over "Resource": "*"', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('Allow', [ + 'secretsmanager:DeleteSecret', + 'secretsmanager:GetSecretValue', + 'secretsmanager:UpdateSecret', + ], ['*']) + await testRule(data, Result.PASS) + }) + + test('No Security Issue when IAM policies that allow full "*:*" administrative privileges', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('Allow', ['*'], ['*']) + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 1.17 Ensure a support role has been created to manage incidents with AWS Support', () => { + const getTestRuleFixture = ( + name: string, + iamUsers: IamUser[], + iamGroups: iamGroup[], + iamRoles: iamRole[] + ): CIS1xQueryResponse => { + return { + queryawsAccount: [ + { + id: cuid(), + iamPolicies: [ + { + name, + iamUsers, + iamGroups, + iamRoles + } + ] + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_117 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when AWSSupportAccess is attached to IAM users', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('AWSSupportAccess', [{arn: 'arn:aws:iam::632941798677:user/test'}], [], []) + await testRule(data, Result.PASS) + }) + + test('No Security Issue when AWSSupportAccess is attached to any IAM groups', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('AWSSupportAccess', [], [{arn: 'arn:aws:iam::632941798677:user/test'}], []) + await testRule(data, Result.PASS) + }) + + test('No Security Issue when AWSSupportAccess is attached to any IAM roles', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('AWSSupportAccess', [], [], [{arn: 'arn:aws:iam::632941798677:user/test'}]) + await testRule(data, Result.PASS) + }) + + test('Security Issue when AWSSupportAccess is not attached to any IAM user, group or role', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('AWSSupportAccess', [], [], []) + await testRule(data, Result.FAIL) + }) + + test('Security Issue when AWSSupportAccess does not exists', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('PolicyTest', [], [], [{arn: 'arn:aws:iam::632941798677:user/test'}]) + await testRule(data, Result.FAIL) + }) + + test('Security Issue when there are no IAM policies', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('', [], [], []) + const account = data.queryawsAccount?.[0] as QueryawsAccount + account.iamPolicies = [] + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed', () => { + const getTestRuleFixture = ( + expiration: string, + ): CIS1xQueryResponse => { + return { + queryawsIamServerCertificate: [ + { + id: cuid(), + expiration + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_119 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when thre not are expired SSL/TLS certificates', async () => { + const day = 1000 * 60 * 60 * 24 + const data: CIS1xQueryResponse = getTestRuleFixture(new Date(Date.now() + 30 * day).toISOString()) + await testRule(data, Result.PASS) + }) + + test('Security Issue when thre are expired SSL/TLS certificates', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(new Date().toISOString()) + await testRule(data, Result.FAIL) + }) + }) +}) diff --git a/src/aws/cis-1.4.0/tests/aws-cis-1.4.0.test.ts b/src/aws/cis-1.4.0/tests/aws-cis-1.4.0.test.ts deleted file mode 100644 index 30b68f60..00000000 --- a/src/aws/cis-1.4.0/tests/aws-cis-1.4.0.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import CloudGraph, { Rule, Result, Engine } from '@cloudgraph/sdk' - - -describe('CIS Amazon Web Services Foundations: 1.4.0', () => { - let rulesEngine: Engine - beforeAll(() => { - rulesEngine = new CloudGraph.RulesEngine({ - providerName: 'aws', - entityName: 'CIS', - }) - }) - - // TODO: Change once we have real checks - describe("Dummy Check", () => { - test('Dummy Test', async () => { - expect('PASS').toBe(Result.PASS) - }) - }) -}) From d9fee96686a2928a2a09abe4f0a370c57d864ab7 Mon Sep 17 00:00:00 2001 From: "mariano.pizarro" Date: Wed, 4 May 2022 11:24:41 -0300 Subject: [PATCH 2/4] Added AWS CIS 1.20 Ensure that IAM Access analyzer is enabled for all regions --- src/aws/cis-1.4.0/README.md | 1 + src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.20.ts | 77 +++++++++++++++++++ src/aws/cis-1.4.0/rules/index.ts | 2 + .../cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts | 62 ++++++++++++++- 4 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.20.ts diff --git a/src/aws/cis-1.4.0/README.md b/src/aws/cis-1.4.0/README.md index 18cc44a7..dedd2a4b 100644 --- a/src/aws/cis-1.4.0/README.md +++ b/src/aws/cis-1.4.0/README.md @@ -69,4 +69,5 @@ Policy Pack based on the [AWS Foundations 1.4.0](https://docs.aws.amazon.com/aud | AWS CIS 1.16 | Ensure IAM policies that allow full "*:*" administrative privileges are not attached | | AWS CIS 1.17 | Ensure a support role has been created to manage incidents with AWS Support | | AWS CIS 1.19 | Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed | +| AWS CIS 1.20 | Ensure that IAM Access analyzer is enabled for all regions | | AWS CIS 1.21 | Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments (Manual) | diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.20.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.20.ts new file mode 100644 index 00000000..6052449b --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.20.ts @@ -0,0 +1,77 @@ +export default { + id: 'aws-cis-1.4.0-1.20', + title: 'AWS CIS 1.20 Ensure that IAM Access analyzer is enabled for all regions', + + description: `Enable IAM Access analyzer for IAM policies about all resources in each region. + + IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region.`, + + audit: `**From Console:** + + 1. Open the IAM console at https://console.aws.amazon.com/iam/ + 2. Choose *Access analyzer* + 3. Click *Analyzers* + 4. Ensure that at least one analyzer is present + 5. Ensure that the *STATUS* is set to *Active* + 6. Repeat these step for each active region + + **From Command Line:** + + 1. Run the following command: + + aws accessanalyzer list-analyzers | grep status + + 2. Ensure that at least one Analyzer the status is set to ACTIVE + 3. Repeat the steps above for each active region. + + If an Access analyzer is not listed for each region or the status is not set to active refer to the remediation procedure below.', + + rationale: 'AWS IAM Access Analyzer helps you identify the resources in your organization and accounts, such as Amazon S3 buckets or IAM roles, that are shared with an external entity. This lets you identify unintended access to your resources and data. Access Analyzer identifies resources that are shared with external principals by using logic-based reasoning to analyze the resource-based policies in your AWS environment. IAM Access Analyzer continuously monitors all policies for S3 bucket, IAM roles, KMS(Key Management Service) keys, AWS Lambda functions, and Amazon SQS(Simple Queue Service) queues.`, + + remediation: `**From Console:** + Perform the following to enable IAM Access analyzer for IAM policies: + + 1. Open the IAM console at https://console.aws.amazon.com/iam/. + 2. Choose *Access analyzer*. + 3. Choose *Create analyzer*. + 4. On the *Create analyzer* page, confirm that the Region displayed is the *Region* where you want to enable Access Analyzer. + 5. Enter a name for the analyzer. *Optional as it will generate a name for you automatically*. + 6. Add any tags that you want to apply to the analyzer. *Optional*. + 7. Choose *Create Analyzer*. + 8. Repeat these step for each active region + + **From Command Line:** + Run the following command: + + aws accessanalyzer create-analyzer --analyzer-name --type + + Repeat this command above for each active region. + **Note:** The IAM Access Analyzer is successfully configured only when the account you use has the necessary permissions.`, + + references: [ + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/what-is-access-analyzer.html', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-getting-started.html', + 'https://docs.aws.amazon.com/cli/latest/reference/accessanalyzer/get-analyzer.html', + 'https://docs.aws.amazon.com/cli/latest/reference/accessanalyzer/create-analyzer.html', + ], + gql: `{ + queryawsAccount { + id + arn + accountId + __typename + iamAccessAnalyzers { + status + } + } + }`, + resource: 'queryawsAccount[*]', + severity: 'high', + conditions: { + path: '@.iamAccessAnalyzers', + array_any: { + path: '[*].status', + equal: 'ACTIVE', + }, + }, +} diff --git a/src/aws/cis-1.4.0/rules/index.ts b/src/aws/cis-1.4.0/rules/index.ts index aba727df..661d7475 100644 --- a/src/aws/cis-1.4.0/rules/index.ts +++ b/src/aws/cis-1.4.0/rules/index.ts @@ -13,6 +13,7 @@ import Aws_CIS_140_115 from './aws-cis-1.4.0-1.15' import Aws_CIS_140_116 from './aws-cis-1.4.0-1.16' import Aws_CIS_140_117 from './aws-cis-1.4.0-1.17' import Aws_CIS_140_119 from './aws-cis-1.4.0-1.19' +import Aws_CIS_140_120 from './aws-cis-1.4.0-1.20' import Aws_CIS_140_121 from './aws-cis-1.4.0-1.21' export default [ @@ -30,5 +31,6 @@ export default [ Aws_CIS_140_116, Aws_CIS_140_117, Aws_CIS_140_119, + Aws_CIS_140_120, Aws_CIS_140_121, ] diff --git a/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts b/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts index d1c73610..504b5d63 100644 --- a/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts +++ b/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts @@ -15,6 +15,7 @@ import Aws_CIS_140_115 from '../rules/aws-cis-1.4.0-1.15' import Aws_CIS_140_116 from '../rules/aws-cis-1.4.0-1.16' import Aws_CIS_140_117 from '../rules/aws-cis-1.4.0-1.17' import Aws_CIS_140_119 from '../rules/aws-cis-1.4.0-1.19' +import Aws_CIS_140_120 from '../rules/aws-cis-1.4.0-1.20' export interface VirtualMfaDevice { serialNumber: string @@ -95,6 +96,10 @@ export interface IamPolicy { iamRoles: iamRole[] } +export interface IamAccessAnalyzer { + status: string +} + export interface QueryawsIamServerCertificate { id: string expiration: string @@ -102,7 +107,8 @@ export interface QueryawsIamServerCertificate { export interface QueryawsAccount { id: string - iamPolicies: IamPolicy[] + iamPolicies?: IamPolicy[] + iamAccessAnalyzers?: IamAccessAnalyzer[] } export interface CIS1xQueryResponse { @@ -848,4 +854,58 @@ describe('CIS Amazon Web Services Foundations: 1.4.0', () => { await testRule(data, Result.FAIL) }) }) + + describe('AWS CIS 1.20 Ensure that IAM Access analyzer is enabled for all regions', () => { + const getTestRuleFixture = ( + status: string, + ): CIS1xQueryResponse => { + return { + queryawsAccount: [ + { + id: cuid(), + iamAccessAnalyzers: [ + { + status, + }, + { + status: 'INACTIVE', + } + ] + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS1xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_120 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when at least one analyzer is enabled', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('ACTIVE') + await testRule(data, Result.PASS) + }) + + test('Security problem when no analyzer is enabled', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('INACTIVE') + await testRule(data, Result.FAIL) + }) + + test('Security Issue when when no analyzer is configured', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('') + const account = data.queryawsAccount?.[0] as QueryawsAccount + account.iamAccessAnalyzers = [] + await testRule(data, Result.FAIL) + }) + }) }) From 52883929bf79350ccc3468a3f5ae60845d227305 Mon Sep 17 00:00:00 2001 From: "mariano.pizarro" Date: Wed, 4 May 2022 15:42:45 -0300 Subject: [PATCH 3/4] Updated 1.7 and 1.20 rules --- src/aws/cis-1.4.0/README.md | 2 +- src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.20.ts | 21 ++++-- src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.21.ts | 2 +- src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.7.ts | 47 +++++++++++--- .../cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts | 64 +++++++++++++++---- 5 files changed, 107 insertions(+), 29 deletions(-) diff --git a/src/aws/cis-1.4.0/README.md b/src/aws/cis-1.4.0/README.md index dedd2a4b..db1828b5 100644 --- a/src/aws/cis-1.4.0/README.md +++ b/src/aws/cis-1.4.0/README.md @@ -70,4 +70,4 @@ Policy Pack based on the [AWS Foundations 1.4.0](https://docs.aws.amazon.com/aud | AWS CIS 1.17 | Ensure a support role has been created to manage incidents with AWS Support | | AWS CIS 1.19 | Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed | | AWS CIS 1.20 | Ensure that IAM Access analyzer is enabled for all regions | -| AWS CIS 1.21 | Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments (Manual) | +| AWS CIS 1.21 | Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments | diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.20.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.20.ts index 6052449b..74d47461 100644 --- a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.20.ts +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.20.ts @@ -60,7 +60,9 @@ export default { arn accountId __typename + regions iamAccessAnalyzers { + region status } } @@ -68,10 +70,19 @@ export default { resource: 'queryawsAccount[*]', severity: 'high', conditions: { - path: '@.iamAccessAnalyzers', - array_any: { - path: '[*].status', - equal: 'ACTIVE', - }, + and: [ + { + path: '@.iamAccessAnalyzers', + isEmpty: false, + }, + { + path: '@', + jq: '[.regions[] as $scanned | { scannedRegion: $scanned, analyzers: [.iamAccessAnalyzers[] | select(.region == $scanned )] }]', + array_all: { + path: '[*].analyzers[0].status', + equal: 'ACTIVE', + }, + }, + ], }, } diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.21.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.21.ts index e5065b20..22420f9b 100644 --- a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.21.ts +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.21.ts @@ -1,6 +1,6 @@ export default { id: 'aws-cis-1.4.0-1.21', - title: 'AWS CIS 1.21 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments (Manual)', + title: 'AWS CIS 1.21 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments', description: 'In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.', diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.7.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.7.ts index 2fe85157..2ff3840f 100644 --- a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.7.ts +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-1.7.ts @@ -1,4 +1,3 @@ -// AWS CIS 1.2.0 Rule equivalent 1.1 export default { id: 'aws-cis-1.4.0-1.7', title: 'AWS CIS 1.7 Eliminate use of the \'root\' user for administrative and daily tasks', @@ -49,22 +48,54 @@ export default { __typename passwordLastUsed passwordEnabled + accessKeysActive + accessKeyData { + lastUsedDate + status + } } }`, resource: 'queryawsIamUser[*]', severity: 'high', conditions: { not: { - and: [ + or: [ { - path: '@.passwordEnabled', - equal: true, + and: [ + { + path: '@.passwordEnabled', + equal: true, + }, + { + value: { daysAgo: {}, path: '@.passwordLastUsed' }, + lessThanInclusive: 90, + }, + ], }, { - value: { daysAgo: {}, path: '@.passwordLastUsed' }, - lessThanInclusive: 30, - }, - ], + and: [ + { + path: '@.accessKeysActive', + equal: true, + }, + { + path: '@.accessKeyData', + array_any: { + and: [ + { + path: '[*].status', + equal: 'Active', + }, + { + value: { daysAgo: {}, path: '[*].lastUsedDate' }, + lessThanInclusive: 90, + }, + ], + }, + }, + ], + } + ] }, }, } diff --git a/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts b/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts index 504b5d63..7fdd02f5 100644 --- a/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts +++ b/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-1.x.test.ts @@ -45,7 +45,6 @@ export interface AssumeRolePolicy { export interface PolicyContent { statement: Statement[] } - export interface QueryawsIamPolicy { id: string policyContent: PolicyContent @@ -63,6 +62,7 @@ export interface QueryawsIamUser { accessKeyData?: AccessKeyData[] iamAttachedPolicies?: IamAttachedPolicy[] inlinePolicies?: string[] + } export interface QueryawsIamPasswordPolicy { @@ -98,6 +98,7 @@ export interface IamPolicy { export interface IamAccessAnalyzer { status: string + region: string } export interface QueryawsIamServerCertificate { @@ -107,6 +108,7 @@ export interface QueryawsIamServerCertificate { export interface QueryawsAccount { id: string + regions?: string[] iamPolicies?: IamPolicy[] iamAccessAnalyzers?: IamAccessAnalyzer[] } @@ -305,7 +307,9 @@ describe('CIS Amazon Web Services Foundations: 1.4.0', () => { describe('AWS CIS 1.7 Eliminate use of the root user for administrative and daily tasks', () => { const getTestRuleFixture = ( - passwordLastUsed: string + passwordLastUsed: string, + status: string, + lastUsedDate: string ): CIS1xQueryResponse => { return { queryawsIamUser: [ @@ -313,6 +317,17 @@ describe('CIS Amazon Web Services Foundations: 1.4.0', () => { id: cuid(), passwordEnabled: true, passwordLastUsed, + accessKeysActive: true, + accessKeyData: [ + { + status, + lastUsedDate, + }, + { + status: 'Active', + lastUsedDate: '2022-01-01T17:20:19.000Z', + } + ], }, ], } @@ -333,13 +348,25 @@ describe('CIS Amazon Web Services Foundations: 1.4.0', () => { expect(processedRule.result).toBe(expectedResult) } - test('No Security Issue when when a root account does not uses his password in the last 30 days', async () => { - const data: CIS1xQueryResponse = getTestRuleFixture('2021-04-08T17:20:19.000Z') + test('No Security Issue when when a root account does not uses his password in the last 90 days', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('2021-04-08T17:20:19.000Z', 'Active', '2021-10-08T17:20:19.000Z') await testRule(data, Result.PASS) }) - test('Security Issue when a root account uses his password in the last 30 days', async () => { - const data: CIS1xQueryResponse = getTestRuleFixture(new Date().toISOString()) + test('No Security Issue when when a root account does not uses his password in the last 90 days and not have access Keys', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('2021-04-08T17:20:19.000Z', '', '') + const user = data.queryawsIamUser?.[0] as QueryawsIamUser + user.accessKeyData = [] + await testRule(data, Result.PASS) + }) + + test('Security Issue when a root account uses his password in the last 90 days', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture(new Date().toISOString(), 'Active', '2021-10-08T17:20:19.000Z') + await testRule(data, Result.FAIL) + }) + + test('Security Issue when a root account uses his access Keys in the last 90 days', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('2021-04-08T17:20:19.000Z', 'Active', new Date().toISOString()) await testRule(data, Result.FAIL) }) }) @@ -857,18 +884,22 @@ describe('CIS Amazon Web Services Foundations: 1.4.0', () => { describe('AWS CIS 1.20 Ensure that IAM Access analyzer is enabled for all regions', () => { const getTestRuleFixture = ( - status: string, + statusRegion1: string, + statusRegion2: string, ): CIS1xQueryResponse => { return { queryawsAccount: [ { id: cuid(), + regions: ['us-east-1', 'us-east-2'], iamAccessAnalyzers: [ { - status, + region: 'us-east-1', + status: statusRegion1, }, { - status: 'INACTIVE', + region: 'us-east-2', + status: statusRegion2, } ] }, @@ -891,18 +922,23 @@ describe('CIS Amazon Web Services Foundations: 1.4.0', () => { expect(processedRule.result).toBe(expectedResult) } - test('No Security Issue when at least one analyzer is enabled', async () => { - const data: CIS1xQueryResponse = getTestRuleFixture('ACTIVE') + test('No Security Issue when at least one analyzer is enabled for all regions', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('ACTIVE','ACTIVE') await testRule(data, Result.PASS) }) - test('Security problem when no analyzer is enabled', async () => { - const data: CIS1xQueryResponse = getTestRuleFixture('INACTIVE') + test('Security Issue when there are an analyzer disabled for some region', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('ACTIVE', 'INACTIVE') + await testRule(data, Result.FAIL) + }) + + test('Security Issue when no analyzer enabled for any region', async () => { + const data: CIS1xQueryResponse = getTestRuleFixture('INACTIVE', 'INACTIVE') await testRule(data, Result.FAIL) }) test('Security Issue when when no analyzer is configured', async () => { - const data: CIS1xQueryResponse = getTestRuleFixture('') + const data: CIS1xQueryResponse = getTestRuleFixture('','') const account = data.queryawsAccount?.[0] as QueryawsAccount account.iamAccessAnalyzers = [] await testRule(data, Result.FAIL) From 300759ba788063ef9be18b24cc77a0d427468b8c Mon Sep 17 00:00:00 2001 From: "mariano.pizarro" Date: Wed, 4 May 2022 17:54:30 -0300 Subject: [PATCH 4/4] feat: Included 2.1.3, 2.1.4, 2.1.5, 2.3.1 rules for aws cis 1.4.0 --- src/aws/cis-1.4.0/README.md | 14 +- .../cis-1.4.0/rules/aws-cis-1.4.0-2.1.3.ts | 75 ++++++ .../cis-1.4.0/rules/aws-cis-1.4.0-2.1.4.ts | 61 +++++ .../cis-1.4.0/rules/aws-cis-1.4.0-2.1.5.ts | 139 +++++++++++ .../cis-1.4.0/rules/aws-cis-1.4.0-2.3.1.ts | 103 ++++++++ src/aws/cis-1.4.0/rules/index.ts | 9 +- .../cis-1.4.0/tests/aws-cis-1.4.0-2.x.test.ts | 224 ++++++++++++++++++ src/aws/cis-1.4.0/tests/aws-cis-1.4.0.test.ts | 19 -- 8 files changed, 616 insertions(+), 28 deletions(-) create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.3.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.4.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.5.ts create mode 100644 src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.3.1.ts create mode 100644 src/aws/cis-1.4.0/tests/aws-cis-1.4.0-2.x.test.ts delete mode 100644 src/aws/cis-1.4.0/tests/aws-cis-1.4.0.test.ts diff --git a/src/aws/cis-1.4.0/README.md b/src/aws/cis-1.4.0/README.md index 56ce3f12..41cea3d0 100644 --- a/src/aws/cis-1.4.0/README.md +++ b/src/aws/cis-1.4.0/README.md @@ -53,11 +53,9 @@ Policy Pack based on the [AWS Foundations 1.4.0](https://docs.aws.amazon.com/aud } ``` - +| Rule | Description | +| ------------- | --------------------------------------------------------------------------------------------------------------------------- | +| AWS CIS 2.1.3 | Ensure MFA Delete is enable on S3 buckets | +| AWS CIS 2.1.4 | Ensure all data in Amazon S3 has been discovered, classified and secured when required | +| AWS CIS 2.1.5 | Ensure that S3 Buckets are configured with 'Block public access (bucket settings)' | +| AWS CIS 2.3.1 | Ensure that encryption is enabled for RDS Instances | diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.3.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.3.ts new file mode 100644 index 00000000..6d1957bf --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.3.ts @@ -0,0 +1,75 @@ +export default { + id: 'aws-cis-1.4.0-2.1.3', + title: 'AWS CIS 2.1.3 Ensure MFA Delete is enable on S3 buckets', + + description: 'Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.', + + audit: `Perform the steps below to confirm MFA delete is configured on an S3 Bucket + + **From Console:** + + 1. Login to the S3 console at https://console.aws.amazon.com/s3/ + 2. Click the _Check_ box next to the Bucket name you want to confirm + 3. In the window under _Properties_ + 4. Confirm that Versioning is _Enabled_ + 5. Confirm that MFA Delete is _Enabled_ + + **From Command Line:** + + 1. Run the get-bucket-versioning + + aws s3api get-bucket-versioning --bucket my-bucket + + Output example: + + + Enabled + Enabled + + + If the Console or the CLI output does not show Versioning and MFA Delete enabled refer to the remediation below.`, + + rationale: 'Adding MFA delete to an S3 bucket, requires additional authentication when you change the version state of your bucket or you delete and object version adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.', + + remediation: `Perform the steps below to enable MFA delete on an S3 bucket. + Note: + -You cannot enable MFA Delete using the AWS Management Console. You must use the AWS CLI or API. + -You must use your 'root' account to enable MFA Delete on S3 buckets. + + **From Command line:** + + 1. Run the s3api put-bucket-versioning command + + aws s3api put-bucket-versioning --profile my-root-profile --bucket Bucket_Name --versioning-configuration Status=Enabled,MFADelete=Enabled`, + + references: [ + 'https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete', + 'https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html', + 'https://aws.amazon.com/blogs/security/securing-access-to-aws-using-mfa-part-3/', + 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_lost-or-broken.html', + ], + gql: `{ + queryawsS3 { + id + arn + accountId + __typename + versioning + mfa + } + }`, + resource: 'queryawsS3[*]', + severity: 'high', + conditions: { + and: [ + { + path: '@.versioning', + equal: 'Enabled', + }, + { + path: '@.mfa', + equal: 'Enabled', + }, + ], + }, +} \ No newline at end of file diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.4.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.4.ts new file mode 100644 index 00000000..071e12d6 --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.4.ts @@ -0,0 +1,61 @@ +export default { + id: 'aws-cis-1.4.0-2.1.4', + title: 'AWS CIS 2.1.4 Ensure all data in Amazon S3 has been discovered, classified and secured when required', + + description: 'Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.', + + audit: `Perform the following steps to determine if Macie is running: + **From Console:** + + 1. Login to the Macie console at https://console.aws.amazon.com/macie/ + 2. In the left hand pane click on By job under findings. + 3. Confirm that you have a Job setup for your S3 Buckets + + When you log into the Macie console if you aren't taken to the summary page and you don't have a job setup and running then refer to the remediation procedure below. If you are using a 3rd Party tool to manage and protect your s3 data you meet this recommendation.`, + + rationale: `Using a Cloud service or 3rd Party software to continuously monitor and automate the process of data discovery and classification for S3 buckets using machine learning and pattern matching is a strong defense in protecting that information. + + Amazon Macie is a fully managed data security and data privacy service that uses machine learning and pattern matching to discover and protect your sensitive data in AWS.`, + + remediation: `Perform the steps below to enable and configure Amazon Macie + **From Console:** + + 1. Log on to the Macie console at https://console.aws.amazon.com/macie/ + 2. Click *Get started*. + 3. Click *Enable Macie*. + + Setup a repository for sensitive data discovery results + + 1. In the Left pane, under Settings, click *Discovery results*. + 2. Make sure *Create bucket* is selected. + 3. Create a bucket, enter a name for the bucket. The name must be unique across all S3 buckets. In addition, the name must start with a lowercase letter or a number. + 4. Click on *Advanced*. + 5. Block all public access, make sure *Yes* is selected. + 6. KMS encryption, specify the AWS KMS key that you want to use to encrypt the results. The key must be a symmetric, customer master key (CMK) that's in the same Region as the S3 bucket. + 7. Click on *Save* + + Create a job to discover sensitive data + + 1. In the left pane, click *S3 buckets*. Macie displays a list of all the S3 buckets for your account. + 2. Select the *check box* for each bucket that you want Macie to analyze as part of the job + 3. Click *Create job*. + 4. Click *Quick create*. + 5. For the Name and description step, enter a name and, optionally, a description of the job. + 6. Then click *Next*. + 7. For the Review and create step, click *Submit*. + + Review your findings + + 1. In the left pane, click *Findings*. + 2. To view the details of a specific finding, choose any field other than the check box for the finding. + + If you are using a 3rd Party tool to manage and protect your s3 data, follow the Vendor documentation for implementing and configuring that tool.`, + + references: [ + 'https://aws.amazon.com/macie/getting-started/', + 'https://docs.aws.amazon.com/workspaces/latest/adminguide/data-protection.html', + 'https://docs.aws.amazon.com/macie/latest/user/data-classification.html', + ], + + severity: 'high', +} \ No newline at end of file diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.5.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.5.ts new file mode 100644 index 00000000..ed3e7299 --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.1.5.ts @@ -0,0 +1,139 @@ +export default { + id: 'aws-cis-1.4.0-2.1.5', + title: 'AWS CIS 2.1.5 Ensure that S3 Buckets are configured with \'Block public access (bucket settings)\'', + + description: 'Amazon S3 provides Block public access (bucket settings) and Block public access (account settings) to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, Block public access (bucket settings) prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, Block public access (account settings) prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.', + + audit: `**If utilizing Block Public Access (bucket settings)** + **From Console:** + + 1. Login to AWS Management Console and open the Amazon S3 console using https://console.aws.amazon.com/s3/ + 2. Select the Check box next to the Bucket. + 3. Click on 'Edit public access settings'. + 4. Ensure that block public access settings are set appropriately for this bucket + 5. Repeat for all the buckets in your AWS account. + + **From Command Line:** + + 1. List all of the S3 Buckets + + aws s3 ls + + 2. Find the public access setting on that bucket + + aws s3api get-public-access-block --bucket + + Output if Block Public access is enabled: + + { + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "IgnorePublicAcls": true, + "BlockPublicPolicy": true, + "RestrictPublicBuckets": true + } + } + + If the output reads false for the separate configuration settings then proceed to the remediation. + + **If utilizing Block Public Access (account settings)** + **From Console:** + + 1. Login to AWS Management Console and open the Amazon S3 console using https://console.aws.amazon.com/s3/ + 2. Choose Block public access (account settings) + 3. Ensure that block public access settings are set appropriately for your AWS account. + + **From Command Line:** + To check Public access settings for this account status, run the following command, + + aws s3control get-public-access-block --account-id --region + + Output if Block Public access is enabled: + + { + "PublicAccessBlockConfiguration": { + "IgnorePublicAcls": true, + "BlockPublicPolicy": true, + "BlockPublicAcls": true, + "RestrictPublicBuckets": true + } + } + + If the output reads *false* for the separate configuration settings then proceed to the remediation.`, + + rationale: `Amazon S3 Block public access (bucket settings) prevents the accidental or malicious public exposure of data contained within the respective bucket(s). + + Amazon S3 Block public access (account settings) prevents the accidental or malicious public exposure of data contained within all buckets of the respective AWS account. + + Whether blocking public access to all or some buckets is an organizational decision that should be based on data sensitivity, least privilege, and use case.`, + + remediation: `**If utilizing Block Public Access (bucket settings)** + **From Console:** + + 1. Login to AWS Management Console and open the Amazon S3 console using https://console.aws.amazon.com/s3/ + 2. Select the Check box next to the Bucket. + 3. Click on 'Edit public access settings'. + 4. Click 'Block all public access' + 5. Repeat for all the buckets in your AWS account that contain sensitive data. + + **From Command Line:** + + 1. List all of the S3 Buckets + + aws s3 ls + + 2. Set the Block Public Access to true on that bucket + + aws s3api put-public-access-block --bucket --public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true" + + **If utilizing Block Public Access (account settings)** + **From Console:** + If the output reads *true* for the separate configuration settings then it is set on the account. + + 1. Login to AWS Management Console and open the Amazon S3 console using https://console.aws.amazon.com/s3/ + 2. Choose Block Public Access (account settings) + 3. Choose Edit to change the block public access settings for all the buckets in your AWS account + 4. Choose the settings you want to change, and then choose Save. For details about each setting, pause on the i icons. + 5. When you're asked for confirmation, enter confirm. Then Click Confirm to save your changes. + + **From Command Line:** + To set Block Public access settings for this account, run the following command: + + aws s3control put-public-access-block --public-access-block-configuration BlockPublicAcls=true, IgnorePublicAcls=true, BlockPublicPolicy=true, RestrictPublicBuckets=true --account-id `, + + references: ['https://docs.aws.amazon.com/AmazonS3/latest/user-guide/block-public-access-account.html'], + gql: `{ + queryawsS3 { + id + arn + accountId + __typename + blockPublicAcls + ignorePublicAcls + blockPublicPolicy + restrictPublicBuckets + } + }`, + resource: 'queryawsS3[*]', + severity: 'high', + conditions: { + and: [ + { + path: '@.blockPublicAcls', + equal: 'Yes', + }, + { + path: '@.ignorePublicAcls', + equal: 'Yes', + }, + { + path: '@.blockPublicPolicy', + equal: 'Yes', + }, + { + path: '@.restrictPublicBuckets', + equal: 'Yes', + }, + ], + }, +} \ No newline at end of file diff --git a/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.3.1.ts b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.3.1.ts new file mode 100644 index 00000000..a2f37551 --- /dev/null +++ b/src/aws/cis-1.4.0/rules/aws-cis-1.4.0-2.3.1.ts @@ -0,0 +1,103 @@ +export default { + id: 'aws-cis-1.4.0-2.3.1', + title: 'AWS CIS 2.3.1 Ensure that encryption is enabled for RDS Instances', + + description: 'Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.', + + audit: `**From Console:** + + 1. Login to the AWS Management Console and open the RDS dashboard at https://console.aws.amazon.com/rds/ + 2. In the navigation pane, under RDS dashboard, click Databases. + 3. Select the RDS Instance that you want to examine + 4. Click Instance Name to see details, then click on Configuration tab. + 5. Under Configuration Details section, In Storage pane search for the Encryption Enabled Status. + 6. If the current status is set to Disabled, Encryption is not enabled for the selected RDS Instance database instance. + 7. Repeat steps 3 to 7 to verify encryption status of other RDS Instance in same region. + 8. Change region from the top of the navigation bar and repeat audit for other regions. + + **From Command Line:** + + 1. Run describe-db-instances command to list all RDS Instance database names, available in the selected AWS region, Output will return each Instance database identifier-name. + + aws rds describe-db-instances --region --query 'DBInstances[*].DBInstanceIdentifier' + + 2. Run again describe-db-instances command using the RDS Instance identifier returned earlier, to determine if the selected database instance is encrypted, The command output should return the encryption status True Or False. + + aws rds describe-db-instances --region --db-instance-identifier --query 'DBInstances[*].StorageEncrypted' + + 3. If the StorageEncrypted parameter value is False, Encryption is not enabled for the selected RDS database instance. + 4. Repeat steps 1 to 3 for auditing each RDS Instance and change Region to verify for other regions`, + + rationale: 'Databases are likely to hold sensitive and critical data, it is highly recommended to implement encryption in order to protect your data from unauthorized access or disclosure. With RDS encryption enabled, the data stored on the instance\'s underlying storage, the automated backups, read replicas, and snapshots, are all encrypted.', + + remediation: `**From Console:** + + 1. Login to the AWS Management Console and open the RDS dashboard at https://console.aws.amazon.com/rds/. + 2. In the left navigation panel, click on Databases + 3. Select the Database instance that needs to encrypt. + 4. Click on Actions button placed at the top right and select Take Snapshot. + 5. On the Take Snapshot page, enter a database name of which you want to take a snapshot in the Snapshot Name field and click on Take Snapshot. + 6. Select the newly created snapshot and click on the Action button placed at the top right and select Copy snapshot from the Action menu. + 7. On the Make Copy of DB Snapshot page, perform the following: + + - In the New DB Snapshot Identifier field, Enter a name for the new snapshot. + - Check Copy Tags, New snapshot must have the same tags as the source snapshot. + - Select Yes from the Enable Encryption dropdown list to enable encryption, You can choose to use the AWS default encryption key or custom key from Master Key dropdown list. + + 8. Click Copy Snapshot to create an encrypted copy of the selected instance snapshot. + 9. Select the new Snapshot Encrypted Copy and click on the Action button placed at the top right and select Restore Snapshot button from the Action menu, This will restore the encrypted snapshot to a new database instance. + 10. On the Restore DB Instance page, enter a unique name for the new database instance in the DB Instance Identifier field. + 11. Review the instance configuration details and click Restore DB Instance. + 12. As the new instance provisioning process is completed can update application configuration to refer to the endpoint of the new Encrypted database instance Once the database endpoint is changed at the application level, can remove the unencrypted instance. + + **From Command Line:** + + 1. Run describe-db-instances command to list all RDS database names available in the selected AWS region, The command output should return the database instance identifier. + + aws rds describe-db-instances --region --query 'DBInstances[*].DBInstanceIdentifier' + + 2. Run create-db-snapshot command to create a snapshot for the selected database instance, The command output will return the new snapshot with name DB Snapshot Name. + + aws rds create-db-snapshot --region --db-snapshot-identifier --db-instance-identifier + + 3. Now run list-aliases command to list the KMS keys aliases available in a specified region, The command output should return each key alias currently available. For our RDS encryption activation process, locate the ID of the AWS default KMS key. + + aws kms list-aliases --region + + 4. Run copy-db-snapshot command using the default KMS key ID for RDS instances returned earlier to create an encrypted copy of the database instance snapshot, The command output will return the encrypted instance snapshot configuration. + + aws rds copy-db-snapshot --region --source-db-snapshot-identifier --target-db-snapshot-identifier --copy-tags --kms-key-id + + 5. Run restore-db-instance-from-db-snapshot command to restore the encrypted snapshot created at the previous step to a new database instance, If successful, the command output should return the new encrypted database instance configuration. + + aws rds restore-db-instance-from-db-snapshot --region --db-instance-identifier --db-snapshot-identifier + + 6. Run describe-db-instances command to list all RDS database names, available in the selected AWS region, Output will return database instance identifier name Select encrypted database name that we just created DB-Name-Encrypted. + + aws rds describe-db-instances --region --query 'DBInstances[*].DBInstanceIdentifier' + + 7. Run again describe-db-instances command using the RDS instance identifier returned earlier, to determine if the selected database instance is encrypted, The command output should return the encryption status True. + + aws rds describe-db-instances --region --db-instance-identifier --query 'DBInstances[*].StorageEncrypted'`, + + references: [ + 'https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html', + 'https://aws.amazon.com/blogs/database/selecting-the-right-encryption-options-for-amazon-rds-and-amazon-aurora-database-engines/#:~:text=With%20RDS%2Dencrypted%20resources%2C%20data,transparent%20to%20your%20database%20engine.', + 'https://aws.amazon.com/rds/features/security/', + ], + gql: `{ + queryawsRdsDbInstance { + id + arn + accountId + __typename + encrypted + } + }`, + resource: 'queryawsRdsDbInstance[*]', + severity: 'high', + conditions: { + path: '@.encrypted', + equal: true, + }, +} \ No newline at end of file diff --git a/src/aws/cis-1.4.0/rules/index.ts b/src/aws/cis-1.4.0/rules/index.ts index c7468a33..2700cbd1 100644 --- a/src/aws/cis-1.4.0/rules/index.ts +++ b/src/aws/cis-1.4.0/rules/index.ts @@ -1,4 +1,11 @@ +import Aws_CIS_140_213 from './aws-cis-1.4.0-2.1.3' +import Aws_CIS_140_214 from './aws-cis-1.4.0-2.1.4' +import Aws_CIS_140_215 from './aws-cis-1.4.0-2.1.5' +import Aws_CIS_140_231 from './aws-cis-1.4.0-2.3.1' export default [ - // TODO: Add rules to export + Aws_CIS_140_213, + Aws_CIS_140_214, + Aws_CIS_140_215, + Aws_CIS_140_231, ] diff --git a/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-2.x.test.ts b/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-2.x.test.ts new file mode 100644 index 00000000..41c411f5 --- /dev/null +++ b/src/aws/cis-1.4.0/tests/aws-cis-1.4.0-2.x.test.ts @@ -0,0 +1,224 @@ +import CloudGraph, { Rule, Result, Engine } from '@cloudgraph/sdk' +import cuid from 'cuid' + +import Aws_CIS_140_213 from '../rules/aws-cis-1.4.0-2.1.3' +import Aws_CIS_140_215 from '../rules/aws-cis-1.4.0-2.1.5' +import Aws_CIS_140_231 from '../rules/aws-cis-1.4.0-2.3.1' + +export interface QueryawsRdsDbInstance { + id: string + encrypted: boolean +} + +export interface QueryawsS3 { + id: string + versioning?: string + mfa?: string + blockPublicAcls?: string + ignorePublicAcls?: string + blockPublicPolicy?: string + restrictPublicBuckets?: string +} +export interface CIS2xQueryResponse { + queryawsS3?: QueryawsS3[] + queryawsRdsDbInstance?: QueryawsRdsDbInstance[] +} + +describe('CIS Amazon Web Services Foundations: 1.4.0', () => { + let rulesEngine: Engine + beforeAll(() => { + rulesEngine = new CloudGraph.RulesEngine({ + providerName: 'aws', + entityName: 'CIS', + }) + }) + + describe('AWS CIS 2.1.3 Ensure MFA Delete is enable on S3 buckets', () => { + const getTestRuleFixture = ( + versioning: string, + mfa: string + ): CIS2xQueryResponse => { + return { + queryawsS3: [ + { + id: cuid(), + versioning, + mfa, + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS2xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_213 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when Versioning and MFA Delete is enable on S3 buckets', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture('Enabled', 'Enabled') + await testRule(data, Result.PASS) + }) + + test('No Security Issue when Versioning is disabled on S3 buckets', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture('Disabled', 'Enabled') + await testRule(data, Result.FAIL) + }) + + test('No Security Issue when MFA Delete is disabled on S3 buckets', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture('Enabled', 'Disabled') + await testRule(data, Result.FAIL) + }) + + test('No Security Issue when Versioning and MFA Delete are disabled on S3 buckets', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture( + 'Disabled', + 'Disabled' + ) + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 2.1.5 Ensure that S3 Buckets are configured with Block public access (bucket settings)', () => { + const getTestRuleFixture = ( + blockPublicAcls: string, + ignorePublicAcls: string, + blockPublicPolicy: string, + restrictPublicBuckets: string + ): CIS2xQueryResponse => { + return { + queryawsS3: [ + { + id: cuid(), + blockPublicAcls, + ignorePublicAcls, + blockPublicPolicy, + restrictPublicBuckets, + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS2xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_215 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when S3 Buckets are configured with Block public access', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture( + 'Yes', + 'Yes', + 'Yes', + 'Yes' + ) + await testRule(data, Result.PASS) + }) + + test('Security Issue when S3 Buckets are not configured with Block public access', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture( + 'No', + 'No', + 'No', + 'No' + ) + await testRule(data, Result.FAIL) + }) + + test('Security Issue when S3 Buckets have a Block public access with blockPublicAcls set to No', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture( + 'No', + 'Yes', + 'Yes', + 'Yes' + ) + await testRule(data, Result.FAIL) + }) + + test('Security Issue when S3 Buckets have a Block public access with ignorePublicAcls set to No', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture( + 'Yes', + 'No', + 'Yes', + 'Yes' + ) + await testRule(data, Result.FAIL) + }) + + test('Security Issue when S3 Buckets have a Block public access with blockPublicPolicy set to No', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture( + 'Yes', + 'Yes', + 'No', + 'Yes' + ) + await testRule(data, Result.FAIL) + }) + + test('Security Issue when S3 Buckets have a Block public access with restrictPublicBuckets set to No', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture( + 'Yes', + 'Yes', + 'Yes', + 'No' + ) + await testRule(data, Result.FAIL) + }) + }) + + describe('AWS CIS 2.3.1 Ensure that encryption is enabled for RDS Instances', () => { + const getTestRuleFixture = (encrypted: boolean): CIS2xQueryResponse => { + return { + queryawsRdsDbInstance: [ + { + id: cuid(), + encrypted, + }, + ], + } + } + + // Act + const testRule = async ( + data: CIS2xQueryResponse, + expectedResult: Result + ): Promise => { + // Act + const [processedRule] = await rulesEngine.processRule( + Aws_CIS_140_231 as Rule, + { ...data } + ) + + // Asserts + expect(processedRule.result).toBe(expectedResult) + } + + test('No Security Issue when RDS instances are encrypted', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture(true) + await testRule(data, Result.PASS) + }) + + test('Security Issue when RDS instances are not encrypted', async () => { + const data: CIS2xQueryResponse = getTestRuleFixture(false) + await testRule(data, Result.FAIL) + }) + }) +}) diff --git a/src/aws/cis-1.4.0/tests/aws-cis-1.4.0.test.ts b/src/aws/cis-1.4.0/tests/aws-cis-1.4.0.test.ts deleted file mode 100644 index 30b68f60..00000000 --- a/src/aws/cis-1.4.0/tests/aws-cis-1.4.0.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import CloudGraph, { Rule, Result, Engine } from '@cloudgraph/sdk' - - -describe('CIS Amazon Web Services Foundations: 1.4.0', () => { - let rulesEngine: Engine - beforeAll(() => { - rulesEngine = new CloudGraph.RulesEngine({ - providerName: 'aws', - entityName: 'CIS', - }) - }) - - // TODO: Change once we have real checks - describe("Dummy Check", () => { - test('Dummy Test', async () => { - expect('PASS').toBe(Result.PASS) - }) - }) -})