Your goal is a weekly answer to "which instances have critical CVEs or open ports?" without installing a third-party scanner. OCI Vulnerability Scanning Service (VSS) does this for compute instances. It has three parts:
- Recipe: what to scan and how often. This covers port scanning, agent-based CVE scanning and CIS benchmark checks.
- Target: which instances or compartments the recipe applies to.
- Results: per-host findings and a tenancy-wide list of vulnerabilities.
This guide uses the OCI agent (the Oracle Cloud Agent plugin). Qualys is the other agent option, and it needs extra cross-tenancy policies that aren't covered here.
Step 1: IAM policies
You need two sets of policies: one for the people running the service and one for the service itself.
Users (put these in the compartment that holds your recipes and targets, or higher):
Allow group SecurityAdmins to manage vss-family in compartment SalesApps
Allow group SecurityAuditors to read vss-family in compartment SalesApps
To let auditors export the reports to CSV, add:
Allow group SecurityAuditors to manage host-agent-scan-results in compartment SalesApps where request.operation = 'ExportHostAgentScanResultCsv'
Allow group SecurityAuditors to manage host-vulnerabilities in compartment SalesApps where request.operation = 'ExportHostVulnerabilityCsv'
The service, which needs these for agent-based scanning so it can deploy and run the agent on your instances:
Allow service vulnerability-scanning-service to manage instances in tenancy
Allow service vulnerability-scanning-service to read compartments in tenancy
Allow service vulnerability-scanning-service to read vnics in tenancy
Allow service vulnerability-scanning-service to read vnic-attachments in tenancy
You can replace in tenancy with in compartment <name> to limit the scope. If the instances' VNICs are in a different compartment from the instances, grant read vnics and read vnic-attachments on that compartment too.
Warning
Creating policies at the tenancy level needs an administrator. Get the policy change approved through your normal process.
manage instancesfor a service principal is broad, so scope it to compartments if your security team prefers.
Step 2: network and agent prerequisites
Agent-based scanning runs on the instance and uploads results to OCI. Check each instance you want to scan:
- Oracle Cloud Agent is running and the Vulnerability Scanning plugin is enabled. The plugin name is shown in the instance's Oracle Cloud Agent tab.
- Private-subnet instances, or any without a public IP, need a service gateway, and the subnet needs a route rule and egress rules to it.
Check the plugin from the CLI:
C=<compartment-ocid>
I=<instance-ocid>
oci instance-agent plugin list --compartment-id $C --instanceagent-id $I --output table
Look for the Vulnerability Scanning plugin with status RUNNING. If it is missing or STOPPED, enable it in the console (Instance > Oracle Cloud Agent tab) or update the instance's agent config. The plugin can take several minutes to start. If plugins show INVALID, troubleshoot the agent first: the usual cause is that the instance can't reach OCI services.
Tip
The scanner's port scan covers public IPs only. If a private instance has no public IP, the port-scan part of the recipe finds nothing for it. That is expected, so rely on the agent results for those instances.
Step 3: create a compute scan recipe
The recipe is easiest to create in the console: Identity & Security > Scanning > Scan Recipes > Create, type Compute.
| Setting | Options | Recommendation |
|---|---|---|
| Public IP port scanning | Standard (1,000 most common ports), Light (100, default), None | Light for most tenancies; Standard for internet-facing workloads |
| Agent-based scanning | Agent: OCI or Qualys | OCI |
| CIS benchmark profile | Strict (Critical if more than 20% fail), Medium (High if more than 40% fail, default), Lightweight (High if more than 80% fail) | Start with Medium |
| File scans (optional) | Checks for log4j and spring4shell only, bi-weekly or monthly | Enable on Java hosts |
| Schedule | Daily or a weekly day | Weekly, the day before your patch window |
Two rules from the documentation:
- If you disable both port scanning and agent-based scanning, nothing assigned to the recipe is scanned.
- Don't change the agent type on an existing recipe. Create a new recipe instead.
The CLI equivalent is oci vulnerability-scanning host scan recipe create, which takes --agent-settings, --port-settings and --schedule as JSON. The JSON shapes vary by CLI version, so run oci vulnerability-scanning host scan recipe create --generate-full-command-json-input to get a template for your build.
List the recipe to get its OCID:
oci vulnerability-scanning host scan recipe list --compartment-id $C --all
Step 4: create a target
A target links a recipe to a compartment. You can optionally limit it to specific instances. If you leave out --instance-ids, every instance in the target compartment is scanned:
oci vulnerability-scanning host scan target create \
--display-name prod-apps-weekly \
--description "All instances in prod-apps" \
--compartment-id $C \
--host-scan-recipe-id <recipe-ocid> \
--target-compartment-id <prod-apps-compartment-ocid>
To scan only selected instances, add --instance-ids '["ocid1.instance.oc1..aaa","ocid1.instance.oc1..bbb"]'.
Confirm the target exists:
oci vulnerability-scanning host scan target list --compartment-id $C --all
Results appear after the first scheduled run. Don't expect them within minutes of creating the target.
Step 5: read the results
Results are stored in the compartment you query. The host-level results come in three types:
# CVEs found by the agent, per host
oci vulnerability-scanning host scan result agent list --compartment-id $C --all
# Open ports found on public IPs
oci vulnerability-scanning host scan result port list --compartment-id $C --all
# CIS benchmark results per host
oci vulnerability-scanning host scan result cis-benchmark list --compartment-id $C --all
For a CVE-centred view ("which hosts have CVE-X?"), use the vulnerability report:
oci vulnerability-scanning vulnerability list --compartment-id $C --all > vss-vulns.json
Field names in the JSON can change between CLI versions. Look at one item first, then build your --query or jq filter from the fields you see:
jq '.data.items[0] // .data[0]' vss-vulns.json
For auditors and patch owners, the console's Scanning > Reports pages let you filter by risk level and export CSV files. That needs the export policies from step 1.
Common problems
| Symptom | Cause | Fix |
|---|---|---|
| Target exists, no agent results after the scheduled run | Plugin not enabled or not running | Enable the Vulnerability Scanning plugin and check instance-agent plugin list |
| Agent results missing only for private instances | No service gateway route or egress rule | Add a service gateway route and egress rules for TCP 443 |
| Port results empty | Instances have no public IP, or port scanning is set to None | Expected behaviour; rely on agent results |
| Scan never runs for anything | Both port and agent scanning disabled in the recipe | Edit the recipe and enable at least one |
NotAuthorizedOrNotFound creating a target | User lacks manage vss-family | Add the user policy |
| Agent scans fail across a compartment | Service policies missing or scoped to the wrong compartment | Add the vulnerability-scanning-service policies |
Prevent it next time
- Make it part of the build. Add the Vulnerability Scanning plugin to your instance configuration or Terraform
agent_config, so new instances are scanned from day one. - Target compartments, not instances. A compartment target picks up new instances automatically. Instance lists go stale.
- Feed findings into patching. Schedule the scan the day before patching, then check the vulnerability list again after the window to confirm the CVEs are gone.
- Route alerts. VSS can raise problems in Cloud Guard. Enable the scanning detectors there so critical findings reach the same triage queue as your other security issues.
- Review the service policies once a year, and remove scanning targets for decommissioned compartments.