
Automating Internal Vulnerability Scanning in AWS with Nessus Manager, Lambda, Secrets Manager, and EventBridge Scheduler
This article walks through a real AWS lab for automating internal vulnerability scans with Nessus Manager, AWS Lambda, AWS Secrets Manager, and Amazon EventBridge Scheduler. It explains why standalone Nessus Professional can list scans through the API, while the scan launch endpoint is available only in Nessus Manager. It then shows how to securely store API credentials, connect Lambda to the private scanner, schedule scan triggers, and validate results using metrics, logs, and scan results.
Introduction
This article is part of a Tenable Nessus on AWS series. In the previous parts, we installed Tenable Nessus Professional on Amazon Linux 2023 with secure remote access, migrated the Nessus instance from a public subnet to a private subnet using an AMI, and performed an internal vulnerability assessment against a private EC2 instance.
Previous articles in this series:
- Installing Tenable Nessus Professional on Amazon Linux 2023 in AWS with Secure Remote Access
https://builder.aws.com/content/3Az1em6D8CiwHy5KxJM9Pk24mig/installing-tenable-nessus-professional-on-amazon-linux-2023-in-aws-with-secure-remote-access - Migrating Tenable Nessus from a Public Subnet to a Private Subnet in AWS Using AMI
https://builder.aws.com/content/3C7I2Ybjvvlwv4jweNL4DSbMm1u/migrating-tenable-nessus-from-a-public-subnet-to-a-private-subnet-in-aws-using-ami - Performing Internal Vulnerability Assessment on a Private EC2 Instance Using Tenable Nessus in AWS
https://builder.aws.com/content/3CR0kq53p3zVe22KfQOGr92ccZQ/performing-internal-vulnerability-assessment-on-a-private-ec2-instance-using-tenable-nessus-in-aws
In the previous article, we performed an internal vulnerability assessment on a private EC2 instance using Tenable Nessus in AWS. That setup worked for manually running scans from the Nessus web interface.
For this continuation, the goal is to automate the scan launch using AWS Lambda. During testing, the standalone Nessus Professional setup showed a limitation. The API was able to list existing scans using GET /scans, but the scan launch endpoint returned:
{"error":"API is not available"}The local Nessus API documentation also showed that the scan launch endpoint
POST /scans/{scan_id}/launchis only usable in Nessus Manager.Because of this standalone Nessus Professional limitation, the setup was updated to Nessus Manager using the available Tenable Agent or Nessus Manager licensing. After switching to Nessus Manager, the scan launch API successfully.
In this article, we will automate the launch of an existing internal Nessus Manager scan using AWS Lambda, AWS Secrets Manager, and Amazon EventBridge Scheduler.
Architecture Overview
The diagram below shows the scheduled scan automation workflow used in this lab. EventBridge Scheduler invokes the Lambda function, Lambda retrieves the Nessus Manager API configuration from AWS Secrets Manager, and then Lambda calls the Nessus Manager API through the private network path to start the internal vulnerability scan.

Step 1: Identify the existing Nessus Manager scan ID
The internal scan was already created in the previous lab. For this step, we only need to confirm the scan ID, which Lambda will use later to trigger the scan through the Nessus Manager API.
For this setup, the existing scan is:
AWS-Target-Hostname-ScanAccess the Nessus Manager web interface using the scanner’s private IP address:
1
https://<PRIVATE_IP_NESSUS_SCANNER>:8834After signing in, go to Scans > My Scans, then open the existing scan.
Check the browser URL and look for the number after
/scans/.Example:
https://<PRIVATE_IP_NESSUS_SCANNER>:8834/#/scans/6In this setup, the scan ID is:
6Record the following details because they will be used in the next steps:
Nessus Manager URL: https://<PRIVATE_IP_NESSUS_SCANNER>:8834
Scan name: AWS-Target-Hostname-Scan
Scan ID: 6
Target: Private EC2 instanceStep 2: Create and validate Nessus Manager API access
Lambda needs API access to authenticate to Nessus Manager and trigger the existing scan. In this step, generate the Nessus Manager API keys and confirm that the API can list and launch the scan.
This validation is important because the scan launch endpoint is available in Nessus Manager. In the earlier standalone Nessus Professional setup, the API could list scans, but the scan launch endpoint was not available.
Sign in to the Nessus Manager web interface, then go to Settings > My Account > API Keys.
Click Generate, confirm the key generation, and copy the generated values:
Access Key
Secret KeyUse placeholders in the article:
accessKey=<YOUR_NESSUS_MANAGER_ACCESS_KEY>
secretKey=<YOUR_NESSUS_MANAGER_SECRET_KEY>Do not expose the real access key or secret key in screenshots, articles, GitHub repositories, or Lambda code.
Next, connect to the Nessus Manager EC2 instance from the AWS Console using SSM Session Manager.
After the terminal session opens, validate that the API can list the available scans:
1
2
curl -k -X GET "https://<PRIVATE_IP_NESSUS_SCANNER>:8834/scans" \
-H "X-ApiKeys: accessKey=<YOUR_NESSUS_MANAGER_ACCESS_KEY>; secretKey=<YOUR_NESSUS_MANAGER_SECRET_KEY>"The response should show the available scans. In this setup, the response included:
AWS-Target-Hostname-ScanWith the scan ID:
6Confirm that Nessus Manager is listening on port
8834:1
sudo ss -lntp | grep 8834The expected result should show Nessus listening on port
8834, similar to:0.0.0.0:8834 [::]:8834This confirms that Nessus Manager is listening on the required port and can be reached through its private IP address.
Before using Lambda, test the scan launch endpoint directly from the Nessus Manager EC2 instance:
1
2
3
4
curl -k -X POST "https://<PRIVATE_IP_NESSUS_SCANNER>:8834/scans/6/launch" \
-H "X-ApiKeys: accessKey=<YOUR_NESSUS_MANAGER_ACCESS_KEY>; secretKey=<YOUR_NESSUS_MANAGER_SECRET_KEY>" \
-H "Content-Type: application/json" \
-d '{}'A successful response should return a
scan_uuid:{
"scan_uuid": "<scan_uuid>"
}After running the command, go back to the Nessus Manager web interface and open:
Scans > AWS-Target-Hostname-ScanConfirm that the scan status changed to:
RunningStep 3: Store the Nessus Manager API configuration in AWS Secrets Manager
The Nessus Manager API keys should not be hardcoded in the Lambda function. Store the Nessus Manager URL, scan ID, access key, and secret key in AWS Secrets Manager so Lambda can retrieve them securely at runtime.
Open AWS Secrets Manager, then click Store a new secret.
- For the secret type, select Other type of secret
Choose the Key/value format and add the following:
| Secret key | Secret value |
|---|---|
| nessus_url | https://<PRIVATE_IP_NESSUS_SCANNER>:8834 |
| scan_id | <scan_id_of_your_scan> |
| access_key | <YOUR_NESSUS_MANAGER_ACCESS_KEY> |
| secret_key | <YOUR_NESSUS_MANAGER_SECRET_KEY> |

Note: Please click Add row for each entry
For Lambda, do not use:
1
https://localhost:8834localhost only works when the command is executed directly from the Nessus Manager EC2 instance. Since Lambda runs separately inside the VPC, it must use the private IP address of the Nessus Manager scanner:1
https://<PRIVATE_IP_NESSUS_SCANNER>:8834- Keep the default encryption key aws/secretsmanager
- Click Next.
- For the Secret name, enter:
1
nessus/aws-internal-scan/api-configFor the Description, enter:
1
Stores Nessus Manager API credentials and scan configuration for the AWS internal vulnerability scan automation.- Click Next.
- Keep automatic rotation disabled for this lab, click Next.
- Review the configuration and click Store.
The Nessus Manager API configuration is now securely stored in AWS Secrets Manager and ready for the Lambda function.
Step 4: Create and configure the Lambda function
In this step, an AWS Lambda function is created to retrieve the Nessus Manager API configuration from AWS Secrets Manager and trigger the existing Nessus Manager scan.
The Lambda function will call
POST /scans/6/launchStep 4.1: Prepare the Lambda security group
- Go to the AWS Console.
- Open EC2.
- Go to Security Groups.
- Click Create security group
- Security group name: lambda-nessus-automation-sg
- VPC: Your custom VPC where Nessus instance is installed.
- For Outbound rules, add the following:
- Type: Custom TCP
- Protocol: TCP
- Port: 8834
- Destination: Nessus Manager security group or
<PRIVATE_IP_NESSUS_SCANNER>/32
- If outbound rules are restricted, also allow HTTPS access to the Secrets Manager VPC endpoint:
- Type: HTTPS
- Protocol: TCP
- Port: 443
- Destination: Secrets Manager endpoint security group
- For the Nessus Manager security group inbound rule, open the security group attached to the Nessus Manager EC2 instance and add the following:
- Type: Custom TCP
- Protocol: TCP
- Port: 8834
- Source:
lambda-nessus-automation-sg
This allows Lambda to reach Nessus Manager privately on port
8834.If AWS shows this error while editing the security group rule:
1
You may not specify a referenced group id for an existing IPv4 CIDR rule.Do the following:
- Delete the incorrect existing IPv4 CIDR rule.
- Click Add rule.
- Create a new rule.
- Use the security group reference as the source or destination.
- Save the rule.
Step 4.2: Create the Lambda Function
- Go to the AWS Console.
- Open Lambda.
- Click Functions.
- Click Create function.
- Select Author from scratch.
- Enter the function name:
1
trigger-nessus-internal-scan- For runtime, select Python 3.14
- Keep the architecture as x86_64
- For the execution role, select Create a new role with basic Lambda permissions
Leave the other options disabled or as default:
Do not click Create function yet. Configure the VPC first.
Step 4.3: Configure the Lambda VPC
- On the Lambda create function page, open the VPC section.
- The Configure VPC panel will appear on the right side.
- Select the same custom VPC as the Nessus Manager EC2 instance.
- Select the private subnet where Nessus Manager is reachable.
- Remove the public subnet if it is selected.
- Select the Lambda security group lambda-nessus-automation-sg
- Click Save in the right side Configure VPC panel.
- Confirm that the VPC section on the main form now shows the selected private subnet and security group.
- After confirming the VPC details, click Create function.
Step 4.4: Update the Lambda execution role
- Open the created Lambda function.
- Go to Configuration.
- Open Permissions.
- Under Execution role, click the role name.
At first, the role only has CloudWatch Logs permissions. Lambda also needs VPC access and permission to read the secret.
- In IAM, click Add permissions.
- Select Attach policies.
- Search for:
1
AWSLambdaVPCAccessExecutionRole- Select the policy.
- Click Add permissions.
This allows Lambda to create and manage network interfaces when running inside a VPC.
Next, add Secrets Manager read access.
- In the same IAM role, click Add permissions.
- Select Create inline policy.
- Choose the JSON tab.
- Paste this policy:
1
2
3
4
5
6
7
8
9
10
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:<ACCOUNT_ID>:secret:nessus/aws-internal-scan/api-config-*"
}
]
}- Replace:
1
<ACCOUNT_ID>with the actual AWS account ID.
- Click Next.
- Name the policy:
1
AllowReadNessusSecret- Click Create policy.
After this, the Lambda execution role should have the following permissions:
- CloudWatch Logs access
- VPC network interface access
- Secrets Manager read access
Step 4.5: Add the Lambda Environment Variable
- Go back to the Lambda function.
- Open Configuration.
- Open Environment variables.
- Click Edit.
- Click Add environment variable.
- Add the following key and value:
- Key:
SECRET_NAME - Value:
nessus/aws-internal-scan/api-config
- Key:
- Click Save.
This tells Lambda which Secrets Manager secret to retrieve.
Step 4.6: Increase the Lambda Timeout
- Open the Lambda function.
- Go to Configuration.
- Open General configuration.
- Click Edit.
- Set the timeout to 1 minute
- Click Save.
This gives Lambda enough time to retrieve the secret and send the request to Nessus Manager.
Step 4.7: Create the Secrets Manager VPC Endpoint
The Lambda function runs inside a private subnet. A Secrets Manager interface VPC endpoint allows Lambda to retrieve the secret privately.
- Go to the AWS Console.
- Open VPC.
- Open Endpoints.
- Click Create endpoint.
- For service category, select AWS services.
- In the service search box, type:
1
secretsmanager- Select this exact service:
1
com.amazonaws.us-east-1.secretsmanagerDo not select services that start with:
1
aws.api.us-east-1- Keep Cross Region endpoint disabled.
- Select the same custom VPC that you're working with
- Enable Private DNS name.
- Set DNS record IP type to IPv4
- Select the private subnet us-east-1b
- Leave Designate IP addresses unchecked.
- Select or create an endpoint security group.
- On the endpoint security group, add this inbound rule:
- Type: HTTPS
- Protocol: TCP
- Port: 443
- Source:
lambda-nessus-automation-sg
- Keep the endpoint policy as default or full access for this lab.
- Click Create endpoint.
- Wait until the endpoint status becomes Available
This endpoint is for Lambda to Secrets Manager on TCP 443
It does not replace the Lambda to Nessus Manager on TCP 8834
Step 4.8: Add the Lambda code
- Open the Lambda function.
- Go to the Code tab.
- Open
lambda_function.py - Delete the default code.
- Paste this code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import json
import os
import ssl
import urllib.request
import urllib.error
import boto3
def get_secret():
secret_name = os.environ["SECRET_NAME"]
client = boto3.client("secretsmanager")
response = client.get_secret_value(SecretId=secret_name)
return json.loads(response["SecretString"])
def lambda_handler(event, context):
config = get_secret()
nessus_url = config["nessus_url"].rstrip("/")
scan_id = str(config["scan_id"])
access_key = config["access_key"]
secret_key = config["secret_key"]
launch_url = f"{nessus_url}/scans/{scan_id}/launch"
headers = {
"X-ApiKeys": f"accessKey={access_key}; secretKey={secret_key}",
"Content-Type": "application/json",
"Accept": "application/json"
}
request_body = json.dumps({}).encode("utf-8")
# Similar to curl -k because Nessus commonly uses a self-signed certificate.
ssl_context = ssl._create_unverified_context()
request = urllib.request.Request(
launch_url,
data=request_body,
headers=headers,
method="POST"
)
try:
with urllib.request.urlopen(request, context=ssl_context, timeout=30) as response:
response_body = response.read().decode("utf-8")
return {
"statusCode": response.getcode(),
"message": "Nessus scan launch request sent successfully.",
"body": json.loads(response_body) if response_body else {}
}
except urllib.error.HTTPError as error:
error_body = error.read().decode("utf-8")
return {
"statusCode": error.code,
"message": "Nessus API returned an error.",
"body": error_body
}
except Exception as error:
return {
"statusCode": 500,
"message": "Lambda failed to launch the Nessus scan.",
"body": str(error)
}- Click Deploy.
If you do not click Deploy, Lambda will test the old code.
Step 4.9: Create the Lambda Test Event
- In Lambda, open the Test section.
- Click Create new test event.
- For event name, enter:
1
ManualNessusScanTest- Keep invocation type as Synchronous.
- Keep event sharing as Private.
- Delete the default JSON:
1
2
3
4
5
{
"key1": "value1",
"key2": "value2",
"key3": "value3"
}- Replace it with:
1
{}- Click Save.
- Click Test or Invoke.
Step 4.10: Validate the Lambda response
A successful Lambda test should return:
1
2
3
4
5
6
7
{
"statusCode": 200,
"message": "Nessus scan launch request sent successfully.",
"body": {
"scan_uuid": "<scan_uuid>"
}
}In the working validation, Lambda returned a
200 response with a scan_uuid.This confirms that Lambda successfully:
- Retrieved the secret from AWS Secrets Manager
- Read the Nessus Manager URL, scan ID, access key, and secret key
- Connected to Nessus Manager using the private IP address
- Sent the scan launch request
- Started the Nessus Manager scan successfully
Step 4.11: Validate the scan in Nessus Manager
- Open the Nessus Manager web interface.
- Go to Scans.
- Open
AWS-Target-Hostname-Scan - Check the scan status.
Expected result:
1
RunningIn the final working test, Nessus Manager showed the scan status as Running, and the scan started after Lambda was invoked.
Step 5: Schedule the Lambda Function Using Amazon EventBridge Scheduler
After confirming that the Lambda function can manually trigger the Nessus Manager scan, the next step is to automate the invocation using Amazon EventBridge Scheduler.
In this setup, EventBridge Scheduler will invoke the Lambda function:
trigger-nessus-internal-scan
The Lambda function will then retrieve the Nessus Manager configuration from AWS Secrets Manager and trigger the existing internal vulnerability scan.
Step 5.1: Open Amazon EventBridge Scheduler
- Go to the AWS Console.
- Search for EventBridge.
- Open Amazon EventBridge.
- In the left navigation pane, go to Scheduler.
- Select Schedules.
- Click Create schedule.
Step 5.2: Specify Schedule Details
On the Specify schedule detail page, configure the schedule name, description, schedule pattern, time zone, cron expression, flexible time window, and timeframe.
Use the following schedule details:
- Schedule name:
weekly-nessus-internal-scan - Description:
Automatically triggers the Nessus Manager internal vulnerability scan using AWS Lambda. - Leave Schedule group as
default.
For the schedule pattern, use the following configuration:
- Select Recurring schedule.
- Set the time zone to (UTC+08:00) Asia/Manila.
- Select Cron-based schedule.
For this lab validation, configure the schedule to run every Wednesday at 8:00 AM Manila time.
Use the following cron values:
- Minutes:
0 - Hours:
8 - Day of month:
? - Month:
* - Day of week:
WED - Year:
*
Cron expression:
1
cron(0 8 ? * WED *)This schedule runs every Wednesday at 8:00 AM Manila time.
For the flexible time window and timeframe, use the following settings:
- Set Flexible time window to Off.
- Leave Start date and time blank.
- Leave End date and time blank.
Leaving the start date blank allows the schedule to become active immediately after it is created. Leaving the end date blank allows the recurring schedule to continue until it is manually disabled or deleted.
Before proceeding, review the Next 10 trigger dates section and confirm that the schedule will run at the expected time.
Click Next.
Step 5.3: Select Target
On Step 2: Select target, configure EventBridge Scheduler to invoke the Lambda function.
Use the following target configuration:
- For Target API, select Templated targets.
- For Target, select AWS Lambda Invoke.
- For Lambda function, select
trigger-nessus-internal-scan
For the payload, use an empty JSON object:
1
{}The payload can remain empty because the Lambda function already retrieves the required Nessus Manager configuration from AWS Secrets Manager, including:
- Nessus Manager URL
- Scan ID
- Access key
- Secret key
After confirming the target configuration, click Next.
Step 5.4: Configure Settings
On Step 3: Settings, configure the schedule state, completion action, retry policy, dead-letter queue, encryption, and permissions.
Use the following settings:
- Set Schedule state to Enabled.
- Leave Action after schedule completion as None.
- Turn Retry policy off for this lab.
- Leave Dead-letter queue as None.
- Leave Encryption as the default setting.
- For Execution role, select Create new role for this schedule.
For the execution role, you can keep the generated role name. For a clearer role name, use:
1
EventBridgeSchedulerInvokeNessusLambdaRoleThis role allows EventBridge Scheduler to invoke the Lambda function.
The required permission is:
1
lambda:InvokeFunctionAfter confirming the settings, click Next.
Step 5.5: Review and Create the Schedule
On Step 4: Review and save schedule, verify the configuration before creating the schedule.
Step 6: Validate the Scheduled Scan Execution
After creating the EventBridge Scheduler schedule, confirm that the scheduled automation successfully invoked the Lambda function and started the Nessus Manager scan.
For this setup, the schedule was configured to trigger the scan at:
1
8:00 AM Asia/ManilaStep 6.1: Check the Lambda Invocation Metrics
Go to AWS Lambda > Functions > trigger-nessus-internal-scan > Monitor
If the metrics do not appear immediately, adjust the time filter. You can change the range to:
1h3h
In this example, the Lambda Monitor page is using the UTC time zone. Since the schedule runs at 8:00 AM Asia/Manila, the invocation can appear around 00:00 UTC
After adjusting the time range, the Invocations graph should show that the Lambda function was invoked around the scheduled time.

Lambda Scheduled Invocation Metrics
This confirms that EventBridge Scheduler invoked the Lambda function.
Step 6.2: Confirm the scheduled scan in Nessus Manager
After confirming the Lambda invocation, open Nessus Manager and go to:
Scans > AWS-Target-Hostname-Scan
Open the scan summary and review the scan details.
Check that the scan started at the scheduled time. For this validation, the scan summary showed that the scan started at:
Today at 8:00 AM
Scheduled Nessus Scan Validation
Also confirm that the scan completed and generated results.
Conclusion
In this article, we automated the launch of an existing internal Nessus Manager scan in AWS. The setup used AWS Lambda to call the Nessus Manager API, AWS Secrets Manager to store the API configuration securely, a Secrets Manager VPC endpoint for private secret retrieval, and Amazon EventBridge Scheduler to trigger the scan automatically.
The automation was validated through Lambda metrics, CloudWatch logs, and the Nessus Manager scan results. The scheduled trigger successfully invoked the Lambda function, the Lambda function retrieved the required secret, and Nessus Manager started the internal vulnerability scan as expected.
This completes the scheduled scan automation workflow for internal vulnerability scanning in AWS. In the next article, we will extend this setup by exporting the completed Nessus scan report and storing it in Amazon S3.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article