{"id":19594,"date":"2023-09-07T10:43:22","date_gmt":"2023-09-07T14:43:22","guid":{"rendered":"https:\/\/qxf2.com\/blog\/?p=19594"},"modified":"2023-09-07T10:43:22","modified_gmt":"2023-09-07T14:43:22","slug":"chef-inspec-aws-resources","status":"publish","type":"post","link":"https:\/\/qxf2.com\/blog\/chef-inspec-aws-resources\/","title":{"rendered":"Auditing AWS cloud resources with Chef InSpec"},"content":{"rendered":"<p>Continuing from the preceding blog, \u2018<a href=\"https:\/\/qxf2.com\/blog\/auditing-os-level-resources-with-chef-inspec-beginners-guide\/\" rel=\"noopener\" target=\"_blank\">Auditing OS Level Resources with Chef InSpec<\/a>\u2019 which delved into utilizing the <a href=\"https:\/\/docs.chef.io\/inspec\/#getting-started-with-chef-inspec\" rel=\"noopener\" target=\"_blank\">Chef InSpec<\/a> open-source tool for testing individual servers via OS level resources. Now, we embark into the domain of Chef InSpec\u2019s facility in cloud environments. Chef InSpec extends its support to cloud platforms like <a href=\"https:\/\/aws.amazon.com\/\" rel=\"noopener\" target=\"_blank\">AWS<\/a>, <a href=\"https:\/\/azure.microsoft.com\/\" rel=\"noopener\" target=\"_blank\">Azure<\/a>, and <a href=\"https:\/\/cloud.google.com\/\" rel=\"noopener\" target=\"_blank\">GCP<\/a>. Referring to insights shared in our earlier blog, <a href=\"https:\/\/qxf2.com\/?utm_source=Chef%20InSpec_aws_level_resource_auditing&#038;utm_medium=click&#038;utm_campaign=From%20blog\" rel=\"noopener\" target=\"_blank\">Qxf2<\/a>\u2019s clients predominantly embrace Infrastructure as Code and heavily lean towards the AWS cloud platform for deployments. A few of our clients also opt for the Azure cloud platform. This post takes through the capabilities of Chef InSpec tailored to the AWS cloud platform.<\/p>\n<hr>\n<h4>1.Prerequisites<\/h4>\n<p>To allow InSpec to talk AWS<br \/>\n-> InSpec installed.<br \/>\n-> AWS console access.<br \/>\n-> AWS IAM user with &#8220;ReadOnlyAccess&#8221; is all you need to execute tests.<br \/>\n-> Configure your <a href=\"https:\/\/aws.amazon.com\/cli\/\" rel=\"noopener\" target=\"_blank\">AWS CLI<\/a><\/p>\n<h4>2.Profile for AWS<\/h4>\n<p>To verify the configuration of <a href=\"https:\/\/docs.chef.io\/inspec\/resources\/#aws\" rel=\"noopener\" target=\"_blank\">AWS resources<\/a>, initialize an inspec profile with target platform as AWS:<\/p>\n<pre lang=\"inspec\">\r\ninspec init profile --platform aws blog_profile\r\n<\/pre>\n<p>The above command creates standalone structure with &#8220;controls&#8221; and &#8220;inspec.yml&#8221; file. You can verify inspec.yml for platform support &#8216;AWS&#8217; under supports section. <\/p>\n<h6>Command to verify AWS profile<\/h6>\n<pre lang=\"inspec\">\r\ninspec detect -t aws:\/\/<region>\/<aws_profile_name>\r\n<\/pre>\n<h6>Output of the Platform details<\/h6>\n<p><img decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/08\/inspec_detect_aws.png\" alt=\"inspec detect\" \/><\/p>\n<hr>\n<h4>3.Tests to verify AWS resources<\/h4>\n<h5>3.1. AWS S3 Resource:<\/h5>\n<p>Amazon <a href=\"https:\/\/aws.amazon.com\/pm\/serv-s3\/\" rel=\"noopener\" target=\"_blank\">S3 bucket<\/a> is object storage service used to store and retrieve the data. This audit resource <code>'aws_s3_bucket'<\/code> tests properties of a single AWS S3 bucket.<br \/>\nExample: The below provided code tests S3 bucket existence, access and the tags attached to the S3 bucket.<br \/>\nBefore writing test add the below steps to <strong>&#8220;inspec.yml&#8221;<\/strong><\/p>\n<pre lang=\"yaml\">\r\natrribute:\r\n- name: bucketname\r\n  description: 's3 bucket name'\r\n  required: true\r\n  value: $TEST_BUCKET\r\n  type: string\r\n<\/pre>\n<p>In this YAML block, you&#8217;re defining an attribute named &#8216;bucketname&#8217;, this attribute used to pass the information to your Chef InSpec profile during runtime. The YAML file describes an S3 bucket name and  the attribute marked as required (required: true). The attribute type set to of type string (type: string). The value for this attribute set to a variable named $TEST_BUCKET.<\/p>\n<pre lang=\"ruby\">\r\nbucketname = attribute('bucketname')\r\n\r\ncontrol \"AWS S3\" do\r\n  impact 0.7\r\n  title \"Check AWS Backend S3 Buckets\"\r\n\r\n  describe aws_s3_bucket(bucket_name: bucketname) do\r\n    it { should exist }\r\n    it { should_not be_public }\r\n    its('tags') { should include(\"Name\" => \"InSpec\")}\r\n  end\r\nend\r\n<\/pre>\n<p>This <code>bucketname = attribute('bucketname')<\/code> retrieves the value of the bucket name. The be_public matcher tests if the bucket has potentially insecure access controls. In summary, the code snippet sets up an attribute in inspec.yml to dynamically provide an S3 bucket name and verifies the existence, not accessible to public and attached tags information.<\/p>\n<h6>Command to execute:<\/h6>\n<pre lang='inspec'>\r\ninspec exec blog_profile -t aws:\/\/<region>\/<aws_profile_name> --input bucketname=\"<bucket name>\"\r\n<\/pre>\n<p>Sample run of s3 bucket resource test:<br \/>\n<img decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/08\/S3_BUCKET_NEW.png\" alt=\"S3_bucket_output_new\" \/><\/p>\n<hr>\n<h5>3.2. AWS SNS:<\/h5>\n<p>An Amazon <a href=\"https:\/\/aws.amazon.com\/sns\/\" rel=\"noopener\" target=\"_blank\">SNS<\/a> is managed service for communication. SNS(Simple Notification Service) used to allow messaging between decoupled microservices applications.<br \/>\nExample: Verify the configuration of an AWS SNS (Simple Notification Service) topic and its associated subscription.<\/p>\n<pre lang=\"ruby\">\r\ndescribe aws_sns_topic('arn:aws:sns:us-east-1:121777381368:my-topic-name') do\r\n    it { should exist }\r\nend\r\ndescribe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1:121777381368:my-topic-name:ef2ddf44-bd3c-41dd-a750-72380deba2a2') do\r\n    its('endpoint') { should cmp 'test@gmail.com' }\r\nend\r\n<\/pre>\n<p>The code validates the existence of an SNS topic and then verifies the attributes of a specific subscription associated with that topic. This helps ensure that the SNS configuration aligns with the expected values and settings.<\/p>\n<hr>\n<h5>3.3. AWS SQS Resource:<\/h5>\n<p>AWS <a href=\"https:\/\/aws.amazon.com\/sqs\/\" rel=\"noopener\" target=\"_blank\">SQS<\/a> queue service used to send, store and receive messages between components. Use <code>aws_sqs_queue<\/code> audit resource for testing its properties of single SQS queue service.<br \/>\nExample: Test the SQS queue exists, delay time, queue is a FIFO queue and  has a visibility timeout of 300 seconds.  <\/p>\n<pre lang=\"ruby\">\r\ndescribe aws_sqs_queue(queue_url: 'https:\/\/sqs.ap-southeast-2.amazonaws.com\/1212121\/MyQueue') do\r\n  it { should exist }\r\n  its('delay_seconds') { should be 0 }\r\n  its('is_fifo_queue') { should be false }\r\n  its('visibility_timeout') { should be 300 }\r\nend\r\n<\/pre>\n<p>The <code>aws_sqs_queue<\/code> resource validates the presence of SQS queue using its URL. The <code>it { should exist }<\/code> assertion confirms its existence, while <code>its('delay_seconds') { should eq 0 }<\/code> test the delay time a specific attribute.The <code>its('is_fifo_queue') { should be false }<\/code> tests if queue is fifo and <code>its('visibility_timeout') { should be 300 } <\/code> tests visibility timeout of the message in seconds.<\/p>\n<hr>\n<h5>3.4. AWS Security Groups Resource:<\/h5>\n<p><a href=\"https:\/\/docs.aws.amazon.com\/vpc\/latest\/userguide\/security-groups.html\" rel=\"noopener\" target=\"_blank\">Security Groups<\/a> acts like firewall that controls the traffic allowed to and from in your <strong>&#8220;Virtual Private Network(VPN)&#8221;<\/strong><br \/>\nExample: The test verifies the existence of Security Group, tests specific incoming ports (such as 80, 443, 22, 7687, and 7474) are allowed, validates that the security group is associated with a designated VPC (Virtual Private Cloud).<\/p>\n<pre lang=\"ruby\">\r\ndescribe aws_security_group(group_id: 'sg-12345678') do\r\n  it { should exist }\r\n  it { should allow_in(port: 80) }\r\n  it { should allow_in(port: 443) }\r\n  it { should allow_in(port: 22) }\r\n  it { should allow_in(port: 7687) }\r\n  it { should allow_in(port: 7474) }\r\n  its ('vpc_id') { should eq 'vpc-12345678' }\r\nend\r\n<\/pre>\n<hr>\n<h5>3.5. AWS Lambda Resource:<\/h5>\n<p>AWS <a href=\"https:\/\/aws.amazon.com\/lambda\/\" rel=\"noopener\" target=\"_blank\">Lambda<\/a> function event-driven, serverless provided as part of Amazon Web Services.<br \/>\nExample: The test verifies the existence of Lambda, tests handler, Lambda version, runtime version and last modified. Please add the below lines to the &#8216;inspec.yml&#8217;.<\/p>\n<pre lang=\"yaml\">\r\nInputs:\r\n- name: lambdaname\r\n  description:  'lambda name'\r\n  type: string\r\n<\/pre>\n<p>In this inspec.yml block, you&#8217;re defining an input (attribute) named &#8216;lambdaname&#8217;. This attribute is used to pass the Lambda function name to your Chef InSpec profile during runtime. It is described with a description stating that it represents a Lambda function name. Its type is specified as a string.<\/p>\n<pre lang=\"ruby\">\r\n# Set a for an input.\r\nlambdaname =  input('lambdaname')\r\n\r\n# verify AWS Lambda Configuration\r\ntitle \"lambda config test\"\r\n \r\n# you add controls here\r\ncontrol \"aws-lambda-config\" do                      \r\n  impact 1.0                               \r\n  title \"verify lambda configuration\"                                       \r\n  describe aws_lambda(lambdaname) do\r\n    it { should exist}\r\n    its ('handler') { should eq 'main.on_event' }\r\n    its ('version') { should eq '$LATEST' }\r\n    its ('runtime') { should eq 'python3.9' }\r\n    its('last_modified') { should_not be_nil }\r\n  end\r\nend\r\n<\/pre>\n<p>The <code>lambdaname = input('lambdaname')<\/code> this line assigns the value of the lambdaname attribute from the input (attribute) defined in the inspec.yml file to the local variable lambdaname. The <code>impact 1.0<\/code> Specifies the impact level of the control. Here, an impact of 1.0 indicates high importance.<br \/>\nIn summary, this code dynamically fetches the Lambda function name using the input function, allowing you to provide the value during runtime. The Chef InSpec control then tests the configuration aspects of the specified AWS Lambda function using the <code>aws_lambda<\/code> resource and various assertions. The &#8220;title&#8221; and &#8220;impact&#8221; attributes provide additional context about the purpose and importance of the tests being performed.<\/p>\n<h6>Command to execute tests under blog_profile:<\/h6>\n<pre lang=\"inspec\">\r\ninspec exec blog_profile -t aws:\/\/<region>\/<aws_profile_name> --input bucketname=\"<S3 bucket name>\" lambdaname=<\"LAMBDA_FUNCTION_NAME\">\r\n<\/pre>\n<p>Note: This command will execute the S3 bucket and Lambda tests.<\/p>\n<hr>\n<h5>3.6. AWS EBS Volume Resource:<\/h5>\n<p>An Amazon <a href=\"https:\/\/docs.aws.amazon.com\/AWSEC2\/latest\/UserGuide\/AmazonEBS.html\" rel=\"noopener\" target=\"_blank\">EBS<\/a>(Elastic block-level Storage) Volume that can attach your instance is a durable, block-level storage device.<br \/>\nExample: The tests verifies existence, confirms that it is encrypted, checks that its size is greater than 50 GB, and ensures that the volume&#8217;s input\/output operations per second (IOPS) is set to exactly 300.<\/p>\n<pre lang=\"ruby\">\r\ndescribe aws_ebs_volume('vol-055a1d9e9b5619d78') do\r\n    it { should exist }\r\n    it { should be_encrypted }\r\n    its('size') { should be > 50 }\r\n    its('iops') { should cmp 300 }\r\nend\r\n<\/pre>\n<hr>\n<h5>3.7. AWS EC2 Instance Resource:<\/h5>\n<p>An Amazon <a href=\"https:\/\/aws.amazon.com\/pm\/ec2\" rel=\"noopener\" target=\"_blank\">EC2<\/a> is virtual service in Amazon web services terminology which can be used to provision a computer server within the AWS cloud.<br \/>\nExample: Test the instance is running, verifying image id, testing tags and the availability zone of an EC2 instance for the provided EC2 instance named &#8216;my-instance&#8217;.<\/p>\n<pre lang=\"ruby\">\r\ndescribe aws_ec2_instances(name: 'my-instance') do\r\n    it { should be_running }\r\n    its('image_id') { should eq 'ami-033a6e7ae709da8ad' }\r\n    its('tags') { should include( \"Name\"=>\"test\",\"Name1\"=>\"test-1\",\"Name2\"=>\"test-2\",\"Name3\"=>\"test-3\") }\r\n    its('availability_zone') { should eq 'us-east-1' }\r\nend\r\n<\/pre>\n<hr>\n<h5>3.8. AWS VPC Resource:<\/h5>\n<p>Use aws_vpc audit resource to test the properties of single <a href=\"https:\/\/docs.aws.amazon.com\/vpc\/latest\/userguide\/what-is-amazon-vpc.html\" rel=\"noopener\" target=\"_blank\">VPC<\/a> and the CIDR Block that is used within the VPC.<br \/>\nExample: Verify that a VPC with ID &#8220;vpc-0123456789abcdef0&#8221; exists and has specific CIDR blocks.<\/p>\n<pre lang=\"ruby\">\r\ndescribe aws_vpc(vpc_id: 'vpc-0123456789abcdef0') do\r\n  it { should exist }\r\n  its('cidr_block') { should cmp '10.0.0.0\/16' }\r\nend\r\n<\/pre>\n<hr>\n<h5>3.9. AWS Elastic IP (EIP) Resource:<\/h5>\n<p>An <a href=\"https:\/\/docs.aws.amazon.com\/AWSEC2\/latest\/UserGuide\/elastic-ip-addresses-eip.html\" rel=\"noopener\" target=\"_blank\">Elastic IP<\/a> address is a static IPv4 address designed for dynamic cloud computing.<br \/>\nExample: Test whether an Elastic IP exists and is correctly associated with the expected EC2 instance.<\/p>\n<pre lang=\"ruby\">\r\nelastic_ip = ENV['ELASTIC_IP']\r\ninstance_id = ENV['INSTANCE_ID']\r\n\r\ncontrol 'Test AWS EC2 instance by providing elastic ip' do\r\n        impact 1.0\r\n        title 'Verify Elastic IP and associated instance ID'\r\n        desc 'Ensure Elastic IP exists and it is associated with the instance ID'\r\n        describe aws_ec2_eip(public_ip: elastic_ip) do\r\n                it { should exist }\r\n                its('instance_id') { should eq instance_id }\r\n        end\r\nend\r\n<\/pre>\n<p>The &#8220;elastic_ip&#8221; and &#8220;instance_id&#8221; retrieve the values of environment variables named &#8216;ELASTIC_IP&#8217; and &#8216;INSTANCE_ID&#8217; during the runtime. The use of environment variables allows flexibility in testing different instances and Elastic IPs.<\/p>\n<hr>\n<h5>3.10.AWS IAM User:<\/h5>\n<p>An <a href=\"https:\/\/aws.amazon.com\/iam\/\" rel=\"noopener\" target=\"_blank\">IAM<\/a> user is an entity in AWS. IAM user is used to interact with AWS console access provided depends on the user permissions.<br \/>\nExample: Test the IAM user &#8216;johny&#8217; exists and don&#8217;t have access key and inline policies attached to the IAM user. <\/p>\n<pre lang=\"ruby\">\r\ndescribe aws_iam_user('johny') do\r\n  it                         { should exist }\r\n  its('access_keys')         { should be_empty }\r\n  its('inline_policy_names') { should be_empty }\r\nend\r\n<\/pre>\n<hr>\n<h4>4.Conclusion<\/h4>\n<p>Infrastructure, especially incorrectly configured infrastructure, is a source of problems. With tools like Chef InSpec, testers now have a way to test for bugs and misconfigurations. I hope the examples in this post help you write tests for your infrastructure hosted on AWS. <\/p>\n<h4>Hire Qxf2 testers for your infrastructure testing<\/h4>\n<p>Hiring Qxf2 for testing infrastructure brings you skilled experts who make sure your systems work smoothly and securely. We find issues before they become problems, ensuring your tech setup is dependable. <a href=\"https:\/\/qxf2.com\/contact?utm_source=Chef%20InSpec_aws_level_resource_auditing&#038;utm_medium=click&#038;utm_campaign=From%20blog\" rel=\"noopener\" target=\"_blank\">Contact us<\/a> to know more.<\/p>\n<hr>\n<h4>References:<\/h4>\n<p><a>https:\/\/qxf2.com\/blog\/auditing-os-level-resources-with-chef-inspec-beginners-guide\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Continuing from the preceding blog, \u2018Auditing OS Level Resources with Chef InSpec\u2019 which delved into utilizing the Chef InSpec open-source tool for testing individual servers via OS level resources. Now, we embark into the domain of Chef InSpec\u2019s facility in cloud environments. Chef InSpec extends its support to cloud platforms like AWS, Azure, and GCP. Referring to insights shared in [&hellip;]<\/p>\n","protected":false},"author":37,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[177,367,380,316],"tags":[],"class_list":["post-19594","post","type-post","status-publish","format-standard","hentry","category-aws","category-chef-inspec","category-iac","category-infrastructure"],"_links":{"self":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/19594","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/users\/37"}],"replies":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/comments?post=19594"}],"version-history":[{"count":88,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/19594\/revisions"}],"predecessor-version":[{"id":21248,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/19594\/revisions\/21248"}],"wp:attachment":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/media?parent=19594"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/categories?post=19594"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/tags?post=19594"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}