This lambda function is meant to allow you to execute InSpec profiles in a serverless fashion. It strives to be as similar as it can be to how you would normally run inspec exec on your CLI, while also adding some useful functionality specific to AWS.
- How can I deploy this lambda function?
- Scan Configuration Examples
- What does the
results_bucketsevent attribute do? - What does the
commandevent attribute do? - What does the
resourcesevent attribute do? - What does the
envevent attribute do? - What does the
eval_tagsevent attribute do? - What does the
results_nameevent attribute do? - What does the
tmp_ssm_ssh_keyevent attribute do? - What does the
ssm_port_forwardevent attribute do? - How can I run profiles with dependencies in an offline environment?
- How do I set up an SSM managed instance?
- Scheduling Recurring Scans
For instructions on how to configure and deploy this Lambda function with Terraform, see TF_EXAMPLE.md
These are examples of the JSON that can be passed into the lambda event to obtain a successful scan.
You can find more details on these configurations and additional configuration options in this README.
Note that if you are running InSpec AWS scans, then the lambda's IAM profile must have suffient permissions to analyze your environment.
{
"command": "inspec exec https://github.com/mitre/aws-foundations-cis-baseline/archive/master.tar.gz -t aws://",
"results_name": "aws-foundations-cis-baseline",
"results_buckets": [
"inspec-results-bucket-dev"
],
"eval_tags": "ServerlessInspec,AwsCisBaseline,AWS"
}{
"command": "inspec exec /tmp/redhat-enterprise-linux-7-stig-baseline-2.6.6.tar.gz -t ssh://[email protected] -i /tmp/id_rsa --sudo --input=disable_slow_controls=true",
"results_name": "redhat-enterprise-linux-7-stig-baseline-inspec-rhel7-test",
"results_buckets": [
"inspec-results-bucket-dev"
],
"eval_tags": "ServerlessInspec,RHEL7,inspec-rhel7-test,SSH",
"resources": [
{
"local_file_path": "/tmp/redhat-enterprise-linux-7-stig-baseline-2.6.6.tar.gz",
"source_aws_s3_bucket": "inspec-profiles-bucket-dev",
"source_aws_s3_key": "redhat-enterprise-linux-7-stig-baseline-2.6.6.tar.gz"
},
{
"local_file_path": "/tmp/id_rsa",
"source_aws_ssm_parameter_key": "/inspec/rhel-7-test/id_rsa"
}
]
}The --proxy_command command line argument is tunneling the session through SSM.
The tmp_ssm_ssh_key defines attributes around a temporary SSH key that will be generated and disposed of during the lifetime of the function execution, which provides temporary access (in a 60 second window) to the SSM managed instance for the function.
{
"command": "inspec exec https://github.com/mitre/redhat-enterprise-linux-7-stig-baseline/archive/master.tar.gz -t ssh://ssm-user@i-00f1868f8f3b4eb03 -i /tmp/tmp_ssh_key --input=disable_slow_controls=true --proxy-command='sh -c \"aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters portNumber=%p\"'",
"results_name": "redhat-enterprise-linux-7-stig-baseline-inspec-rhel7-test",
"results_buckets": [
"inspec-results-bucket-dev"
],
"eval_tags": "ServerlessInspec,RHEL7,inspec-rhel7-test,SSH-SSM",
"tmp_ssm_ssh_key": {
"host": "i-00f1868f8f3b4eb03",
"user": "ssm-user",
"key_name": "tmp_ssh_key"
}
}{
"command": "inspec exec https://github.com/mitre/redhat-enterprise-linux-7-stig-baseline/archive/master.tar.gz -t awsssm://i-00f1868f8f3b4eb03 --input=disable_slow_controls=true",
"results_name": "redhat-enterprise-linux-7-stig-baseline-inspec-rhel7-test",
"results_buckets": [
"inspec-results-bucket-dev"
],
"eval_tags": "ServerlessInspec,RHEL7,inspec-rhel7-test,AWSSSM"
}Note that the target is set to winrm://localhost because port forwarding is being set up with the ssm_port_forward event property.
{
"command": "inspec exec /tmp/microsoft-windows-server-2019-stig-baseline-1.3.10.tar.gz -t winrm://localhost --password $WIN_PASS",
"results_name": "windows-server-2019-stig-baseline-inspec-win2019-test",
"results_buckets": [
"inspec-results-bucket-dev"
],
"eval_tags": "ServerlessInspec,WinSvr2019,inspec-win2019-test,WinRM",
"resources": [
{
"local_file_path": "/tmp/microsoft-windows-server-2019-stig-baseline-1.3.10.tar.gz",
"source_aws_s3_bucket": "inspec-profiles-bucket-dev",
"source_aws_s3_key": "microsoft-windows-server-2019-stig-baseline-1.3.10.tar.gz"
},
{
"env_variable": "WIN_PASS",
"source_aws_secrets_manager_secret_name": "/inspec/inspec-win2019-test/password"
}
],
"ssm_port_forward": {
"instance_id": "i-0e35ab216355084ee",
"ports": [5985, 5986]
}
}{
"command": "inspec exec /tmp/microsoft-windows-server-2019-stig-baseline-1.3.10.tar.gz -t awsssm://i-00f1868f8f3b4eb03",
"results_name": "windows-server-2019-stig-baseline-inspec-win2019-test",
"results_buckets": [
"inspec-results-bucket-dev"
],
"eval_tags": "ServerlessInspec,WinSvr2019,inspec-win2019-test,AWSSSM",
"resources": [
{
"local_file_path": "/tmp/microsoft-windows-server-2019-stig-baseline-1.3.10.tar.gz",
"source_aws_s3_bucket": "inspec-profiles-bucket-dev",
"source_aws_s3_key": "microsoft-windows-server-2019-stig-baseline-1.3.10.tar.gz"
},
],
}{
"command": "inspec exec https://gitlab.dsolab.io/scv-content/inspec/kubernetes/baselines/k8s-cluster-stig-baseline/-/archive/master/k8s-cluster-stig-baseline-master.tar.gz -t k8s://",
"results_name": "k8s-cluster-stig-baseline-dev-cluster",
"results_buckets": [
"inspec-results-bucket-dev"
],
"eval_tags": "ServerlessInspec,k8s",
"resources": [
{
"local_file_path": "/tmp/kube/config",
"source_aws_s3_bucket": "inspec-profiles-bucket-dev",
"source_aws_s3_key": "kube-dev/config"
},
{
"local_file_path": "/tmp/kube/client.crt",
"source_aws_ssm_parameter_key": "/inspec/kube-dev/client_crt"
},
{
"local_file_path": "/tmp/kube/client.key",
"source_aws_ssm_parameter_key": "/inspec/kube-dev/client_key"
},
{
"local_file_path": "/tmp/kube/ca.crt",
"source_aws_ssm_parameter_key": "/inspec/kube-dev/ca_crt"
}
],
"env": {
"KUBECONFIG": "/tmp/kube/config"
}
}Database scans have not been tested yet with this lambda function.
"https://github.com/mitre/aws-rds-crunchy-data-postgresql-9-stig-baseline"The results_buckets event attribute defines S3 buckets that the function will push JSON results to.
If you DO NOT specify the results_buckets parameter in the lambda event, then the results will just be logged to CloudWatch. If you DO specify the results_buckets parameter in the lambda event, then the lambda will attempt to save the results JSON to the S3 bucket under unprocessed/*. The format of the JSON is meant to be a incomplete API call to push results to a Heimdall Server and looks like this:
{
"data": {}, // this contains the HDF results
"eval_tags": "<eval_tags from event attribute>"
}The results_bucket event parameter format looks like the following:
{
"...": "...",
"results_buckets": [
"inspec-results-bucket-dev"
]
}The command event attribute defines the inspec exec command that the lambda function will execute. Note that --show-progress --reporter cli json:<results_name> will be appended to the end of the command attribute before execution.
This MUST be an inspec exec command. Read more about inspec exec here
{
"command": "inspec exec /tmp/redhat-enterprise-linux-7-stig-baseline-2.6.6.tar.gz -t ssh://root@host -i /tmp/id_rsa --sudo --input=disable_slow_controls=true",
"...": "..."
}The resources event attribute defines what files and/or environment variables are needed prior to executing the InSpec command. This might be a tar.gz of an InSpec profile stored in S3, a Windows password stored in SSM Parameter store, etc.
You may define a resources as needing to be downloaded as a local file on disk (must be located within /tmp/), or as needing have their contents stored in an environment variable. Downloaded files and environment variable resources will be usable by your inspec exec ... command.
{
"resources": [
{
"local_file_path": "/tmp/microsoft-windows-server-2019-stig-baseline-1.3.10.tar.gz",
"...": "...",
}
],
}{
"resources": [
{
"env_variable": "WIN_PASS",
"...": "..."
}
],
}The possible sources for the lamdba's resources are defined below:
Resources may be downloaded from an S3 bucket. Ensure that you lambda's IAM role has s3:getObject permissions for the desired bucket/object.
{
"resources": [
{
"...": "...",
"source_aws_s3_bucket": "inspec-profiles-bucket-dev",
"source_aws_s3_key": "microsoft-windows-server-2019-stig-baseline-1.3.10.tar.gz"
},
]
}Resources may be fetched from AWS SSM Parameter Store. Ensure that you lambda's IAM role has kms:Decrypt permissions for the secrets's KMS key and has ssm:GetParameter permissions for the parameter.
{
"resources": [
{
"...": "...",
"source_aws_ssm_parameter_key": "/inspec/kube-dev/client_crt"
}
]
}Resources may be fetched from AWS Secrets Manager. Ensure that you lambda's IAM role has kms:Decrypt permissions for the secrets's KMS key and secretsmanager:GetSecretValue permissions for the secret.
{
"resources": [
{
"...": "...",
"source_aws_secrets_manager_secret_name": "/inspec/kube-dev/client_crt"
}
]
}The env event attribute allows definition of static envrionment variables that are needed by the InSpec command. Note that you may not overwrite an existing environment varaible.
{
"...": "...",
"env": {
"KUBECONFIG": "/tmp/kube/config",
"OTHER_ENV": "value"
}
}The eval_tags event attribute allows definition of comma separated Heimdall eval_tags that will be passed through to the results file.
{
"...": "...",
"eval_tags": "hostname,profile,etc"
}The results_name event attribute defines the filename for generated InSpec scan results. If this is not set, then the results_name will default to unnamed_profile.
{
"...": "...",
"results_name": "human-readable-name-of-my-results"
}The tmp_ssm_ssh_key event attribute allows the function to push temporary SSH keys to a linux-based SSM managed instance. These keys are generated as needed and are disposed of on the target machine after 60 seconds.
This method of InSpec scanning works with the following sequence of events:
- Generate a SSH key pair within the lambda function
- Use the train-awsssm plugin to send the public key material to
~/.ssh/authorized_keysusing SSM Send Command - Immedately queue another SSM Send Command to remove the key from
~/.ssh/authorized_keysafter 60 seconds - Start an SSH session using the generated key pair and execute the InSpec scan over SSH
Assumptions with this method:
- Scanning linux-based instances (i.e. not Windows)
- The instance has the following commands installed:
su,mkdir,touch,echo,sleep,grep,mv - The user that runs "SSM Send Command" commands is priviledged to write to any user's
~/.sshdirectory (this should default to root unless explicitly changed)
This method is advantageous over using the awsssm:// transport by itself because invoking all InSpec commands over SSM Send Command is significantly slower than over SSH.
{
"...": "...",
"tmp_ssm_ssh_key": {
"host": "i-00f1868f8f3b4eb03",
"user": "ssm-user",
"key_name": "tmp_ssh_key"
}
}The tmp_ssm_ssh_key event attribute defines local ports to be forwarded to a specific SSM managed instance. This is useful if the lambda function does not have direct network access to the machine, but both the lambda and machine have access to SSM.
Note that forwarding local ports will mean that you will need to connect to localhost for your inspec exec command (e.g., inspec exec ... -t winrm://localhost)
{
"...": "...",
"ssm_port_forward": {
"instance_id": "i-0e35ab216355084ee",
"ports": [5985, 5986]
}
}The recommendation for offline environments is to save vendored InSpec profiles to an S3 bucket.
git clone [email protected]:mitre/aws-foundations-cis-baseline.git
inspec vendor ./aws-foundations-cis-baseline && inspec archive ./aws-foundations-cis-baseline
# Then upload ./aws-foundations-cis-baseline.tar.gz to you S3 bucketYou can make an EC2 instance a SSM managed instance using this guide. This also requires that your EC2 instance has the SSM agent software installed on it. Some AWS-provided images already have this installed, but if it is not already installed on you instance then you can use this guide to get it installed.
The recommended way to set up recurring scans is to create an Event Rule within AWS CloudWatch.
You can do this via the AWS Console using the following steps:
- Navigate to the CloudWatch service and click
ruleson the left-hand side - Click the
Create Rulebutton - Instead of
Event Pattern, chosse theScheduleoption and either use CRON or a standard schedule confugration - Click
Add a Targetwith the type ofLambda Functionand select the Serverless InSpec function - Expand
Configure Inputand chooseConstant (JSON text) - Paste your configuration into the
Constant (JSON text)field (this will be passed to the lambda event each time it is triggered)
© 2019-2021 The MITRE Corporation.
Approved for Public Release; Distribution Unlimited. Case Number 18-3678.
MITRE hereby grants express written permission to use, reproduce, distribute, modify, and otherwise leverage this software to the extent permitted by the licensed terms provided in the LICENSE.md file included with this project.
This software was produced for the U. S. Government under Contract Number W56KGU-18-D-0004, and is subject to Federal Acquisition Regulation Clause 52.227-14, Rights in Data-General.
No other use other than that granted to the U. S. Government, or to those acting on behalf of the U. S. Government under that Clause is authorized without the express written permission of The MITRE Corporation.