- Project State: Maintained
For more information on project states and SLAs, see this documentation.
This InSpec resource pack uses the AWS Ruby SDK v3 and provides the required resources to write tests for resources in AWS.
Valid AWS credentials are required, see AWS Documentation
There are multiple ways to set the AWS credentials, as shown below:
Set your AWS credentials in a .envrc file or export them in your shell. (See example .envrc file)
# Example configuration
export AWS_ACCESS_KEY_ID="AKIAJUMP347SLS66IGCQ"
export AWS_SECRET_ACCESS_KEY="vD2lfoNvPdwsofqyuO9jRuWUkZIMqisdfeFmkHTy7ON+w"
export AWS_REGION="eu-west-3"
export AWS_AVAILABILITY_ZONE="eu-west-3a" Set your AWS credentials in ~/.aws/config and ~/.aws/credentials file. (See example aws configure credentials)
Example ~/.aws/credentials :
[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
[engineering]
aws_access_key_id=AKIAIOSFODNN7EXAMPLF
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY1Example ~/.aws/config :
[default]
region=us-west-2
[engineering]
region=us-east-2AWS SDK selects the default credentials unless aws_profile is set in an .envrc.
# Example configuration
export AWS_PROFILE="engineering"- Credentials set in
.envrcOR as an Environment variable. - Credentials set in
~/.aws/credentialsAND~/.aws/configANDAWS_PROFILEset as an Environment variable. - Credentials set in
~/.aws/credentialsAND~/.aws/configANDAWS_PROFILEis NOT set as an Environment variable. Default credentials are used.
The aws_region parameter queries resources in a specific region. If not provided, the AWS region set in environment variables or configuration files are used.
Example:
describe aws_ec2_instances(aws_region: 'us-west-2') do
its('count') { should eq 10 }
endAssuming an IAM role allows an IAM users gain additional (or different) permissions to perform actions in a different AWS account. (See example aws configure IAM role)
Example:
[profile example_profile]
role_arn = arn:aws:iam::123456789012:role/example_profile
source_profile = user1Each resource requires specific permissions to perform the operations required for testing. For example, to test an AWS EC2 instance, your service principal requires the ec2:DescribeInstances and iam:GetInstanceProfile permissions. You can find a comprehensive list of each resource's permissions needed in the documentation.
Since this is an InSpec resource pack, it defines the InSpec resources and includes example tests only. To use the AWS resources in your tests, do the following:
inspec init profile --platform aws my-profileThe above command generates a sample inspec.yml that depends on master. We recommend this is pinned to a release of the resource pack as follows:
name: my-profile
title: My own AWS profile
version: 0.1.0
inspec_version: '>= 4.6.9'
depends:
- name: inspec-aws
url: https://github.com/inspec/inspec-aws/archive/x.tar.gz
supports:
- platform: awsSince this is an InSpec resource pack, it only defines InSpec resources. To use these resources in your controls, create your profile:
inspec init profile --platform aws my-profileThe above command generates a sample inspec.yml that depends on master. We recommend this is pinned to a release of the resource pack as follows.
Example inspec.yml:
name: my-profile
title: My own AWS profile
version: 0.1.0
inspec_version: '>= 4.6.9'
depends:
- name: inspec-aws
url: https://github.com/inspec/inspec-aws/archive/x.tar.gz
supports:
- platform: aws(For available inspec-aws versions, see this list of inspec-aws versions.)
If a resource is in local, change the url to path.
name: my-profile
title: My own AWS profile
version: 0.1.0
inspec_version: '>= 4.6.9'
depends:
- name: inspec-aws
path: ../my-profile
supports:
- platform: aws(For available inspec-aws versions, see this list of inspec-aws versions.)
Add some tests and run the profile via:
inspec exec my-profile -t aws://This resource pack allows the testing of the following AWS resources. If a resource you wish to test is not listed, please feel free to open an Issue. As an open-source project, we also welcome public contributions via Pull Request.
InSpec AWS Supported Resources https://docs.chef.io/inspec/resources/
For disallowing FTP, we check that there is no ingress from 0.0.0.0/0 on port 21. The below sample control loops across all regions, checking all security groups for the account:
title 'Test AWS Security Groups Across All Regions For an Account Disallow FTP'
control 'aws-multi-region-security-group-ftp-1.0' do
impact 1.0
title 'Ensure AWS Security Groups disallow FTP ingress from 0.0.0.0/0.'
aws_regions.region_names.each do |region|
aws_security_groups(aws_region: region).group_ids.each do |security_group_id|
describe aws_security_group(aws_region: region, group_id: security_group_id) do
it { should exist }
it { should_not allow_in(ipv4_range: '0.0.0.0/0', port: 21) }
end
end
end
end describe aws_ec2_instance(name: 'ProdWebApp') do
it { should be_running }
its('image_id') { should eq 'ami-27a58d5c' }
end describe aws_iam_users.where( has_mfa_enabled: false) do
it { should_not exist }
endTo provide multi-region support, the aws_region property is specified to a resource. This property affects AWS resources that have a region dependency. For example, security groups. One special case worth mentioning is the aws_s3_bucket resource that updates its region based on the location returned from S3.
The aws_regions resource is used to loop across all regions.
aws_regions.region_names.each do |region|
<use region in other resources here>
endA custom endpoint URL can optionally be specified to resources for testing other compatible providers. This propagates to the AWS client configuration. An example is provided below for Minio S3 compatible buckets.
title 'Test For Minio Buckets Existing at a Custom Endpoint'
endpoint = attribute(:minio_server, value: 'http://127.0.0.1:9000', description: 'The Minio server custom endpoint.')
control 'minio-buckets-1.0' do
impact 1.0
title 'Ensure Minio buckets exist.'
describe aws_s3_bucket(aws_endpoint: endpoint, bucket_name: 'miniobucket') do
it { should exist }
end
describe aws_s3_bucket(aws_endpoint: endpoint, bucket_name: 'notthere') do
it { should_not exist }
end
end{{< note >}}
The InSpec AWS assumes full compatibility with the underlying AWS SDK, and unsupported operations cause failures. Hence, depending on the external provider implementation, your mileage may vary!
{{< /note >}}
In certain cases, AWS implements rate-limiting. To mitigate this issue, the Retry Limit and Retry Backoff can be set in two ways:
Setting AWS_RETRY_LIMIT and AWS_RETRY_BACKOFF environment variables is implemented at the session level.
export AWS_RETRY_LIMIT=5
export aws_retry_limit=5Note environment variables are case insensitive.
InSpec AWS resources now support setting the Retry Limit and Retry Backoff at the control level, as shown below.
describe aws_config_recorder(recorder_name: aws_config_recorder_name, aws_retry_limit=5, aws_retry_backoff=5) do
it { should exist }
its('recorder_name') { should eq aws_config_recorder_name }
end#####The aws_retry_limit and aws_retry_backoff precedence:
- Set at Inspec control level.
- Set at Environment level.
Retry Limit and Retry Backoff documentation
InSpec AWS resources returns NullResponse when an undefined property is tested from version 1.24 onwards instead of raising a NoMethodError.
describe aws_ec2_instance(instance_id: 'i-12345678') do
its('fake_property') { should be_nil }
end
# => EC2 Instance i-12345678
# ✔ fake_property is expected to be nil
describe aws_ec2_instance(instance_id: 'i-12345678') do
its('instance_ID') { should eq 'i-12345678' }
end
# => × instance_ID is expected to eq "i-12345678"
# expected: "i-12345678"
# got: #<#<Class:0x00007ffc4aa24c68>::NullResponse:0x00007ffc39f16070>
# (compared using ==)Prior to version 1.24.
describe aws_ec2_instance(instance_id: 'i-12345678') do
its('fake_property') { should be_nil }
end
# => EC2 Instance i-12345678
# × fake_property
# undefined method `fake_property' for EC2 Instance i-12345678
describe aws_ec2_instance(instance_id: 'i-12345678') do
its('instance_ID') { should eq 'i-12345678' }
end
# => undefined method `instance_ID' for EC2 Instance i-12345678InSpec AWS depends on version 3 of the AWS SDK provided via Train AWS. InSpec depends on Train AWS, so this is not explicitly listed in the Gemfile here.
A Dockerfile is provided at the root of this resource pack repository.
cd inspec-aws
docker build -t inspec-aws -f Dockerfile
docker run -it inspec-aws /bin/bash
export AWS_ACCESS_KEY_ID=<your creds here>
export AWS_SECRET_ACCESS_KEY=<your creds here>
bundle exec inspec exec sample_profile -t aws://If successful, output similar to below code is seen:
# bundle exec inspec exec sample_profile -t aws://
Profile: AWS InSpec Profile (InSpec AWS Sample Profile)
Version: 0.1.0
Target: aws://us-east-1
✔ aws-vpcs-multi-region-status-check: Check AWS VPCs in all regions have status "available"
✔ VPC vpc-1234abcd in eu-north-1 should exist
✔ VPC vpc-1234abcd in eu-north-1 should be available
<curtailing> ...
Profile: Amazon Web Services Resource Pack (inspec-aws)
Version: 0.1.0
Target: aws://us-east-1
No tests were executed.
Profile Summary: 1 successful control, 0 control failures, 0 controls skipped
Test Summary: 50 successful, 0 failures, 0 skippedrake test TEST=inspec-aws/test/unit/resources/aws_alb_test.rbThe above example is for running the aws_alb_test.rb file.
Run the linting and unit tests via the below:
$ bundle exec rake
Running RuboCop...
Inspecting 2 files
..
2 files inspected, no offenses detected
/Users/spaterson/.rubies/ruby-2.4.3/bin/ruby -I"lib:libraries:test/unit" -I"/Users/spaterson/.rubies/ruby-2.4.3/lib/ruby/gems/2.4.0/gems/rake-12.3.1/lib" "/Users/spaterson/.rubies/ruby-2.4.3/lib/ruby/gems/2.4.0/gems/rake-12.3.1/lib/rake/rake_test_loader.rb" "test/unit/resources/aws_vpc_test.rb"
Run options: --seed 64195
# Running:
.................
Fabulous run in 0.253300s, 67.1141 runs/s, 51.3225 assertions/s.
17 runs, 13 assertions, 0 failures, 0 errors, 0 skips
bundle exec inspec check /Users/spaterson/Documents/workspace/aws/inspec-aws
Location: /Users/spaterson/Documents/workspace/aws/inspec-aws
Profile: inspec-aws
Controls: 0
Timestamp: 2018-11-29T15:02:33+00:00
Valid: true
! No controls or tests were defined.
Summary: 0 errors, 1 warningsConversely, run using within a docker container, using the make file:
To run unit tests and linting:
make sure
Will result in...
make sure
docker-compose run --rm builder
Running RuboCop...
Inspecting 68 files
....................................................................
68 files inspected, no offenses detected
/usr/local/bin/ruby -I"lib:libraries:test/unit" -I"/usr/local/bundle/gems/rake-12.3.3/lib" "/usr/local/bundle/gems/rake-12.3.3/lib/rake/rake_test_loader.rb" "test/unit/resources/aws_alb_test.rb" "test/unit/resources/aws_auto_scaling_group_test.rb" "test/unit/resources/aws_cloudformation_stack_test.rb" "test/unit/resources/aws_cloudtrail_trail_test.rb" "test/unit/resources/aws_cloudtrail_trails_test.rb" "test/unit/resources/aws_cloudwatch_alarm_test.rb" "test/unit/resources/aws_cloudwatch_log_metric_filter_test.rb" "test/unit/resources/aws_config_delivery_channel_test.rb" "test/unit/resources/aws_config_recorder_test.rb" "test/unit/resources/aws_dynamodb_table_test.rb" "test/unit/resources/aws_ebs_volume_test.rb" "test/unit/resources/aws_ebs_volumes_test.rb" "test/unit/resources/aws_ec2_instance_test.rb" "test/unit/resources/aws_ec2_instances_test.rb" "test/unit/resources/aws_ecr_test.rb" "test/unit/resources/aws_ecs_cluster_test.rb" "test/unit/resources/aws_eks_cluster_test.rb" "test/unit/resources/aws_eks_clusters_test.rb" "test/unit/resources/aws_elb_test.rb" "test/unit/resources/aws_flow_log_test.rb" "test/unit/resources/aws_hosted_zones_test.rb" "test/unit/resources/aws_iam_account_alias_test.rb" "test/unit/resources/aws_iam_group_test.rb" "test/unit/resources/aws_iam_password_policy_test.rb" "test/unit/resources/aws_iam_policy_test.rb" "test/unit/resources/aws_iam_role_test.rb" "test/unit/resources/aws_iam_root_user_test.rb" "test/unit/resources/aws_iam_saml_provider_test.rb" "test/unit/resources/aws_iam_user_test.rb" "test/unit/resources/aws_kms_key_test.rb" "test/unit/resources/aws_kms_keys_test.rb" "test/unit/resources/aws_launch_configuration_test.rb" "test/unit/resources/aws_organizations_member_test.rb" "test/unit/resources/aws_rds_instance_test.rb" "test/unit/resources/aws_rds_instances_test.rb" "test/unit/resources/aws_region_test.rb" "test/unit/resources/aws_regions_test.rb" "test/unit/resources/aws_route_table_test.rb" "test/unit/resources/aws_route_tables_test.rb" "test/unit/resources/aws_s3_bucket_object_test.rb" "test/unit/resources/aws_s3_bucket_test.rb" "test/unit/resources/aws_s3_buckets_test.rb" "test/unit/resources/aws_security_group_test.rb" "test/unit/resources/aws_security_groups_test.rb" "test/unit/resources/aws_sns_subscription_test.rb" "test/unit/resources/aws_sns_topic_test.rb" "test/unit/resources/aws_sns_topics_test.rb" "test/unit/resources/aws_sqs_queue_test.rb" "test/unit/resources/aws_sts_caller_identity_test.rb" "test/unit/resources/aws_subnet_test.rb" "test/unit/resources/aws_subnets_test.rb" "test/unit/resources/aws_vpc_test.rb" "test/unit/resources/aws_vpcs_test.rb"
Run options: --seed 22010
# Running:
..............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Fabulous run in 4.613042s, 155.6457 runs/s, 172.3375 assertions/s.
718 runs, 795 assertions, 0 failures, 0 errors, 0 skips
To run the full suite of tests, run
make doubly_sure
This test runs the unit tests, creates the target infrastructure, and runs the intergration tests. If successful, the test automatically destroy everything. If it fails, it will keep the environment up, testing then can be achieved by running:
make int_testThe AWS credentials can either be supplied via environmental variables or files located on ./aws folder.
This requires docker, docker-compose and make, see Three Musketeers Pattern for details.
Running the integration tests (after setup_integration_tests):
$ bundle exec rake test:run_integration_tests
----> Run
bundle exec inspec exec test/integration/verify --attrs test/integration/build/aws-inspec-attributes.yaml; rc=$?; if [ $rc -eq 0 ] || [ $rc -eq 101 ]; then exit 0; else exit 1; fi
Profile: Amazon Web Services Resource Pack (inspec-aws)
Version: 0.1.0
Target: aws://eu-west-2
✔ aws-vpc-1.0: Ensure AWS VPC has the correct properties.
✔ VPC vpc-0373aeb7284407ffd should exist
✔ VPC vpc-0373aeb7284407ffd should not be default
✔ VPC vpc-0373aeb7284407ffd cidr_block should eq "10.0.0.0/27"
✔ VPC vpc-0373aeb7284407ffd instance_tenancy should eq "dedicated"
✔ VPC vpc-0373aeb7284407ffd vpc_id should eq "vpc-0373aeb7284407ffd"
✔ VPC vpc-0373aeb7284407ffd state should eq "available"
✔ VPC vpc-0373aeb7284407ffd dhcp_options_id should eq "dopt-f557819d"
✔ VPC default should exist
✔ VPC default should be default
✔ VPC default vpc_id should eq "vpc-1ea06476"
✔ VPC vpc-0373aeb7284407ffd should exist
✔ VPC vpc-0373aeb7284407ffd should not be default
✔ VPC vpc-0373aeb7284407ffd vpc_id should eq "vpc-0373aeb7284407ffd"
...
Profile: Amazon Web Services Resource Pack (inspec-aws)
Version: 0.1.0
Target: aws://eu-west-2
No tests were executed.
Profile Summary: 50 successful controls, 0 control failures, 3 controls skipped
Test Summary: 602 successful, 0 failures, 18 skippedIf an error occurs when running "inspec exec" on a newly created AWS profile, check that the AWS transport is specified as below:
inspec exec . -t aws://If a method missing error occurs and all the steps documented above is followed try running the following command within the profile directory:
inspec vendor --overwriteThe InSpec AWS resources are community-supported. For bugs and features, please open a GitHub issue and label it appropriately.
This work builds on the InSpec 2 AWS resources that are originally shipped as part of InSpec.