Hardening Oracle Cloud Infrastructure – Part 2: Remediation

In the first blog part, I wrote that’s not so easy to identify risk in your Oracle Cloud Infrastructure account. CIS – Center of Internet Security – has a free benchmark which supports you in hardening your account. And with Palo Alto Prisma or OCI Cloud Guard, there are two tools which provide information too. But I want to have an easier way to identify and remediate dangers.

select * from cloud;

Steampipe.io provides a powerful CLI tool, where you can query cloud account by API. Instead if clicking actions in the user interface to find out who has no MFA enabled, just execute this query:

steampipe query "select name, is_mfa_activated from oci_identity_user where is_mfa_activated=false;"
+---------------------------------------------------------+------------------+
| name                                                    | is_mfa_activated |
+---------------------------------------------------------+------------------+
| gordon.shumway                                          | false            |
| homer.simpson                                           | false            |
+---------------------------------------------------------+------------------+

But, steampipe.io is not only for Oracle Cloud Infrastructure, it offers a wide bandwidth of plugins for other products like Azure, Amazon Web Services, Docker and many more.

Querying your cloud environment is only one feature of Steampipe. By modules – Steampipe calls them Mods – you can run dashboards and create reports based on your API information.

There are three mods available:

Oracle Cloud Compliance ModCIS Benchmark – Actually 33 Controls available
OCI Insights ModCreate dashboards and reports for your OCI resources
Oracle Cloud Thrifty ModChecks for unused resources and opportunities

My favorite module is the Oracle Cloud Compliance Mod to run the CIS benchmark. Let’s use it in my WSL2 environment.

Steampipe Architecture

Basics

Steampipe can run in two modes. Service mode is optimized for automated, continuous data collection and analysis, while normal mode is optimized for ad-hoc queries.

  • Normal Mode: Every time you execute a query, the embedded PostgreSQL engine is ad-hoc executed, results are cached. The caching behavior can be changed in the plugin configuration file.
  • Service Mode: Steampipe runs permanently as service and provides a SQL endpoint for PostgreSQL clients with address/username/password to connect.

Details

In the background, PostgreSQL uses the Foreign Data Wrapper method, to provide the information as tables. Steampipe can run in service mode as standalone or in a Docker container. Both is well described on the steamipe.io page.

CLI Setup

The CLI tool can be installed on every platform, follow the installation guide and setup the OCI plugin. A quick installation in Windows Subsystem for Linux looks like this:

-- install steampipe
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/turbot/steampipe/main/install.sh)"
-- install steampipe plugin
steampipe plugin install steampipe
-- install oci plugin
steampipe plugin install oci

Follow the steps in the installation guide for the plugin, it needs additionally an OCI IAM user with permissions and an API key This setup is similar when you want to use the OCI CLI. If you have already installed OCI CLI on your environment, Steampipe can benefit of the existing configuration.

In this log post here is a another section how to setup the plugin properly: GitHub – martinberger-ch/oci-monitoring. Recommendation for the group policy:

Allow group {group_name} to read all-resources in tenancy
Allow group {group_name} to manage all-resources in tenancy where request.operation='GetConfiguration'

If the settings are done, you can do a first check if everything works properly – simple query for the OCI home region:

$ steampipe query "select key,title,status from oci_region where is_home_region=true;"
+-----+-------------+--------+
| key | title       | status |
+-----+-------------+--------+
| ZRH | eu-zurich-1 | READY  |
+-----+-------------+--------+

To get a list of available Oracle Cloud Infrastructire tables, see here: Oracle Cloud Infrastructure plugin | Steampipe Hub.

CIS Benchmark – CLI

After the successful CLI setup, install the Oracle Cloud Compliance Mod from the Git repository and run the benchmark.

$ git clone https://github.com/turbot/steampipe-mod-oci-compliance.git
$ cd steampipe-mod-oci-compliance

Run the CIS benchmark. Actually 33 controls (checks are executed). An excerpt of the results:

$ steampipe check all

| | + 1.7 Ensure MFA is enabled for all users with a console password .........................................  7 /   7 [=         ]
| | | |
| | | ALARM: tenant-admin password login enabled but no MFA device configured. .......................................... kestenholz1
| | | ALARM: gordon.shumway password login enabled but no MFA device configured. ........................................ kestenholz1

| | + 2.2 Ensure no security lists allow ingress from 0.0.0.0/0 to port 3389 ..................................  2 /  10 [==        ]
| | | |
| | | ALARM: sl-zrh-t-public-001 contains 1 ingress rule(s) allowing port 3389 from 0.0.0.0/0. ....... eu-zurich-1 kestenholz1 public
| | | ALARM: devops-security-list-public contains 1 ingress rule(s) allowing port 3389 from 0.0.0.0/0. eu-zurich-1 kestenholz1 devops
| | | OK   : Default Security List for vcn-zrh-t-public-001 ingress restricted for port 3389 from 0.0… eu-zurich-1 kestenholz1 public
| | | OK   : Default Security List for vcn-zrh-t-oracle-lab-ipsec-priv-001 ingress restricted for… eu-zurich-1 kestenholz1 oracle-lab

| | + 3.9 Ensure a notification is configured for VCN changes .................................................  1 /   3 [==        ]
| | | |
| | | ALARM: IAM LOGIN not configured for VCN changes. ................................................. eu-zurich-1 kestenholz1 root
| | | OK   : VCN CREATE,DELETE,UPDATE configured for VCN changes. ...................................... eu-zurich-1 kestenholz1 root

To run a specific control, add the control number. Example for check 2.1:

$ steampipe check control.cis_v110_2_1

+ 2.1 Ensure no security lists allow ingress from 0.0.0.0/0 to port 22 .......................................... 5 / 10 [==========]
  |
  ALARM: devops-security-list-public contains 1 ingress rule(s) allowing SSH from 0.0.0.0/0. ......... eu-zurich-1 kestenholz1 devops
  ALARM: Default Security List for devops-vcn contains 1 ingress rule(s) allowing SSH from 0.0.0.0/0.  eu-zurich-1 kestenholz1 devops
  ALARM: devops-security-list-private contains 1 ingress rule(s) allowing SSH from 0.0.0.0/0. ........ eu-zurich-1 kestenholz1 devops
  ALARM: Default Security List for vcn-zrh-t-public-001 contains 1 ingress rule(s) allowing SSH from … eu-zurich-1 kestenholz1 public
  ALARM: Default Security List for vcn-fra-t-oracle-lab-ipsec-priv-001 contains 1 ingress rule… eu-frankfurt-1 kestenholz1 oracle-lab
  OK   : sl-zrh-t-oracle-lab-ipsec-priv-001 ingress restricted for SSH from 0.0.0.0/0. ........... eu-zurich-1 kestenholz1 oracle-lab
  OK   : devops-happy-list ingress restricted for SSH from 0.0.0.0/0. ................................ eu-zurich-1 kestenholz1 devops
  OK   : sl-fra-t-oracle-lab-ipsec-priv-001 ingress restricted for SSH from 0.0.0.0/0. ........ eu-frankfurt-1 kestenholz1 oracle-lab
  OK   : sl-zrh-t-public-001 ingress restricted for SSH from 0.0.0.0/0. .............................. eu-zurich-1 kestenholz1 public
  OK   : Default Security List for vcn-zrh-t-oracle-lab-ipsec-priv-001 ingress restricted for SSH… eu-zurich-1 kestenholz1 oracle-lab

Summary

OK ................................................................................................................... 5 [=====     ]
SKIP ................................................................................................................. 0 [          ]
INFO ................................................................................................................. 0 [          ]
ALARM ................................................................................................................ 5 [=====     ]
ERROR ................................................................................................................ 0 [          ]

TOTAL ........................................................................................................... 5 / 10 [==========]

CIS Benchmark – Dashboard

Start the local dashboard to get the check results in a browser. A small web server is started on port 9194. You can always stop the dashboard.

$ steampipe dashboard
[ Wait    ] Loading Workspace
[ Wait    ] Starting Dashboard Server
[ Message ] Workspace loaded
[ Message ] Initialization complete
[ Ready   ] Dashboard server started on 9194 and listening on local
[ Message ] Visit http://localhost:9194
[ Message ] Press Ctrl+C to exit

Here you can see the results in an overview and drill down in each check. Looks like there is a lot of work to do for me.

Grafana loves Steampipe – A CIS Benchmark Live Dashboard

Now we bring the power of Steampipe and Grafana together for a live dashboard of the actual benchmark stats. Grafana can use PostgreSQL as a data source. The steps:

  1. Start Steampipe in Service Mode
  2. Get PostgreSQL connection string
  3. Configure GrafanaData Source
  4. Create a new Dashboard and add a panel with a query
  5. Add more Panels with CIS Information

As I wrote above, first we start Steampipe in the Service Mode. This works in Docker environments too. Here in this case, I am running Steampipe native and Grafana in a Docker setup.

Start Steampipe in Service Mode

You can see the endpoint. The password is not shown actually.

$ steampipe service start
Steampipe service is running:

Database:

  Host(s):            localhost, 127.0.0.1, 172.27.19.253
  Port:               9193
  Database:           steampipe
  User:               steampipe
  Password:           ********* [use --show-password to reveal]
  Connection string:  postgres://steampipe@localhost:9193/steampipe

Managing the Steampipe service:

  # Get status of the service
  steampipe service status

  # View database password for connecting from another machine
  steampipe service status --show-password

  # Restart the service
  steampipe service restart

  # Stop the service
  steampipe service stop

Get PostgreSQL Connection String

$ steampipe service status --show-password
Steampipe service is running:

Database:

  Host(s):            localhost, 127.0.0.1, 172.27.19.253
  Port:               9193
  Database:           steampipe
  User:               steampipe
  Password:           4766_44e6_9f23
  Connection string:  postgres://steampipe:4766_44e6_9f23@localhost:9193/steampipe

Managing the Steampipe service:

  # Get status of the service
  steampipe service status

  # View database password for connecting from another machine
  steampipe service status --show-password

  # Restart the service
  steampipe service restart

  # Stop the service
  steampipe service stop

Now we are ready to connect Grafana to Steampipe. Feel free to use a PosgreSQL client like pgAdmin to verify the connection.

Configure Grafana Data Source

Login in Grafana and create a new data source of type PostgreSQL based on the connection string and the password your got. Leave the other settings as is. Test the data source.

Create a new Dashboard and add a Panel with a Query

First we want to get an information how many user have MFA enabled according CIS rule 1.7 Ensure MFA is enabled for all users with a console password. The query:

select count(*) from oci_identity_user where is_mfa_activated=false;

Use the panel type Stat and add the code. Run the query to verify the result. Here in this account, 7 users are found where MFA is not enabled. Now it’s up to you, to set a proper refresh rate in the Grafana dashboard and add more values.

Add more Panels with CIS Information

Some more query examples based on the CIS benchmark:

-- 1.8 Ensure user API keys rotate within 90 days or less
select count(*) 
from oci_identity_api_key
where time_created <= (current_date - interval '90' day);

-- 3.15 Ensure Cloud Guard is enabled in the root compartment of the tenancy
select
  case
    when status = 'ENABLED' then 'CloudGuard enabled.'
    else 'CloudGuard disabled.'
  end as reason
from
  oci_cloud_guard_configuration a
  left join oci_identity_tenancy as c on c.tenant_id = a.tenant_id;

-- 4.1.1 Ensure no Object Storage buckets are publicly visible
select count(*)
from
  oci_objectstorage_bucket as a
  left join oci_identity_compartment as c on c.id = a.compartment_id
where public_access_type !='NoPublicAccess';

But where to get all the queries behind the CIS benchmark? As Steampipe uses the same method like we do to gather information by select * from cloud;, the information behind the checks are available on the steampipe.io homepage. Each CIS control is described here: Controls | Oracle Cloud Infrastructure Compliance mod | Steampipe Hub.

When you select the CIS control here, for example 1.10 Ensure user auth tokens rotate within 90 days or less control | Oracle Cloud Infrastructure Compliance mod | Steampipe Hub and you scroll down the page, you can see the SQL used behind. And when you click on the named query, you get the details. When no details is available, feel free to write your own queries.

Example Dashboard

This is and example of a Grafana Dashboard with a 30mins refresh rate and a mix between stats panel and tables.

What’s next

Running Steampipe in Service Mode is perfect to gather live data from your Oracle Cloud Infrastructure account to build your own dashboards. Use Grafana functions like alerting so you are up to date, when someone creates a VCN where Flow Logging is disabled or API keys are too old.

If you are interested in history, you can use other tools like Apache Superset to gather information and visualize the outputs or store the actual state on a regular base in another database instance. Lucas Jellema @AMISnl wrote a blog post about here: Visual Dashboard on Oracle Cloud Infrastructure using Apache Superset and Steampipe – AMIS, Data Driven Blog – Oracle & Microsoft Azure.

select * from cloud; – I love it!