--- title: About the aws_iam_users Resource platform: aws --- # aws\_iam\_users Use the `aws_iam_users` Chef InSpec audit resource to test properties of a all or multiple users. To test properties of a single user, use the `aws_iam_user` resource. To test properties of the special AWS root user (which owns the account), use the `aws_iam_root_user` resource.
## Availability ### Installation This resource is distributed along with Chef InSpec itself. You can use it automatically. ### Version This resource first became available in v2.0.16 of InSpec. ## Syntax An `aws_iam_users` resource block uses a filter to select a group of users and then tests that group. With no filter, it returns all AWS IAM users. # No filter # We expect 42 users describe aws_iam_users do its('usernames.count') { should eq 42 } end # Using a filter # All users should have MFA (no user without MFA should exist) describe aws_iam_users.where(has_mfa_enabled?: false) do it { should_not exist } end ## Examples The following examples show how to use this Chef InSpec audit resource. ### Test that all users have Multi-Factor Authentication enabled describe aws_iam_users.where(has_mfa_enabled?: false) do it { should_not exist } end ### Test that at least one user has a console password to log into the AWS web console describe aws_iam_users.where(has_console_password?: true) do it { should exist } end ### Test that all users who have a console password have Multi-Factor Authentication enabled console_users_without_mfa = aws_iam_users .where(has_console_password?: true) .where(has_mfa_enabled?: false) describe console_users_without_mfa do it { should_not exist } end ### Test that all users who have a console password have used it at least once console_users_with_unused_password = aws_iam_users .where(has_console_password?: true) .where(password_never_used?: true) describe console_users_with_unused_password do it { should_not exist } end ### Test that at least one user exists who has a console password and has used it at least once console_users_with_used_password = aws_iam_users .where(has_console_password?: true) .where(password_ever_used?: true) describe console_users_with_used_password do it { should exist } end ### Test that users with passwords that have not been used for 90 days do not describe aws_iam_users.where { password_last_used_days_ago > 90 } do it { should_not exist } end
## Filter Criteria You may pass filter criteria to `where` to narrow down the result set. ### has\_attached\_policies True or false. Filters the users to include only those that have at least one IAM managed policy attached to the user. # Don't attach policies to users describe aws_iam_users.where(has_attached_policies: true) do it { should_not exist } end ### has\_console\_password True or false. Filters the users to include only those that have a console password (that is, they are able to login to the AWS web UI using a password). # No console passwords for anyone describe aws_iam_users.where(has_console_password: true) do it { should_not exist } end ### has\_inline\_policies True or false. Filters the users to include only those that have at least one IAM policy directly embedded in the user record. # Embedding policies is usually hard to manage describe aws_iam_users.where(has_inline_policies: true) do it { should_not exist } end ### has\_mfa\_enabled True or false. Filters the users to include only those that have some kind of Mult-Factor Authentication enabled (virtual or hardware). # Require MFA for everyone describe aws_iam_users.where(has_mfa_enabled: false) do it { should_not exist } end ### password\_ever\_used True or false. Filters the users to include only those that have used their password at least once. # Someone should have used their password describe aws_iam_users.where(password_ever_used: true) do it { should exist } end ### password\_last\_used_days\_ago Integer. Filters the users to include only those who used their password a certain number of days ago. '0' means today. # Bob should login every day describe aws_iam_users.where(password_ever_used: true, password_last_used_days_ago:0) do its('usernames') { should include 'bob' } end # This filter is often more useful in block mode, using a greater-than # Here, audit users who have not logged in in the last 30 days describe aws_iam_users.where do password_ever_used && password_last_used_days_ago > 30 end do it { should_not exist' } end ### password\_never\_used True or false. Filters the users to include only those that have used _never_ their password. # No zombie accounts! describe aws_iam_users.where(password_never_used: true) do it { should_not exist } end ### username String. Filters the users to include only those whose username matches the value you provide. # Block mode example (recommended) # Service users should not have a password describe aws_iam_users.where { username.start_with?('service') } do it { should_not have_console_password } end # Method call example. This is a poor use of aws_iam_users (plural); # if you want to audit an individual user whose username you know, use # aws_iam_user (singular) # Verify Bob exists describe aws_iam_users.where(username: 'bob') do it { should exist } end ## Properties Properties are used with the `its` test to obtain information about the matched users. Properties always return arrays, though they may be empty. ### attached\_policy\_arns Array of strings. Each entry is the ARN of an IAM managed policy that is attached to at least one matched user. The list is de-duplicated, so if you have five users that are all attached to the same policy, `attached_policy_arns` will return only one ARN, not five. # Service users should be attached to a custom service policy describe aws_iam_users.where { username.start_with?('service') } do its('attached_policy_arns') { should include 'arn:aws:iam::123456789012:policy/MyServicePolicy' } end ### attached\_policy\_names Array of strings. Each entry is the friendly name of an IAM managed policy that is attached to at least one matched user. The list is de-duplicated, so if you have five users that are all attached to the same policy, `attached_policy_names` will return only one name, not five. # Service users should be attached to a custom service policy # and not include Admin policy! describe aws_iam_users.where { username.start_with?('service') } do its('attached_policy_names') { should include 'MyServicePolicy' } its('attached_policy_names') { should_not include 'AdministratorAccess' } end ### inline\_policy\_names Array of strings. Each entry is the name of an embedded policy that is embedded in at least one matched user. Keep in mind that each user has a copy of a policy (which can then be modified). This means that two users can have an embedded policy with the same name, but very different contents. The list is de-duplicated, so if you have five users that have an inline policy with the same name, `inline_policy_names` will return only one name, not five. # Service users should have a bespoke policy describe aws_iam_users.where { username.start_with?('service') } do its('inline_policy_names') { should include 'some-bespoke-policy' } end ### usernames Array of strings. Each entry is the name of a user that matched. There will be exactly as many usernames here as there were users that matched, though it is possible to have non-unique usernames. # 42 Users, including Bob, should have a password. describe aws_iam_users.where(has_console_password: true) do its('usernames') { should include 'bob' } its('usernames.count') { should eq 42 } end ## Matchers This Chef InSpec audit resource has the following resource-specific matchers. For a full list of available matchers, please visit our [universal matchers page](https://www.inspec.io/docs/reference/matchers/). As a plural resource, all matchers beginning with `have_` will return true if _any_ of the selected users match. ### exist The test passes if the filtered user set is not empty. This basic matcher is frequently used with `should_not` to detect undesired conditions. # Require MFA for everyone describe aws_iam_users.where(has_mfa_enabled: false) do it { should_not exist } end ### have\_attached\_policies The test passes if at least one user in the filtered set has at least one attached IAM managed policy. # Bachelors don't have attachments describe aws_iam_users.where { username =~ /bachelor/ } do it { should_not have_attached_policies } end ### have\_console\_password The test passes if at least one user in the filtered set has a console password. describe aws_iam_users do it { should_not have_console_password } end ### have\_inline\_policies The test passes if at least one user in the filtered set has at least one embedded policy. # No one should have an inline policy describe aws_iam_users do it { should_not have_inline_policies } end ### have\_mfa\_enabled The test passes if at least one user in the filtered set has MFA enabled (virtual or hardware). # At least one person should use MFA. # This does not mean ALL users have MFA. describe aws_iam_users do it { should have_mfa_enabled } end ## AWS Permissions Your [Principal](https://docs.aws.amazon.com/IAM/latest/UserGuide/intro-structure.html#intro-structure-principal) will need the `iam:ListUsers`, `iam:GetLoginProfile`, `iam:ListMFADevices`, `iam:ListAccessKeys`, `iam:ListUserPolicies`, and `iam:ListAttachedUserPolicies` action with Effect set to Allow. You can find detailed documentation at [Actions, Resources, and Condition Keys for Identity And Access Management](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_identityandaccessmanagement.html).