V-72999

Severity: Medium

Generated

2019-05-20 15:48:11.984914

Status

Failed

PostgreSQL must separate user functionality (including user interface services) from database management functionality.

NIST 800-53

STIG # Description Result
SC-2 SC-2: Application Partitioning failed

Guidance

Information system management functionality includes functions necessary to administer databases, network components, workstations, or servers and typically requires privileged user access.

The separation of user functionality from information system management functionality is either physical or logical and is accomplished by using different computers, different central processing units, different instances of the operating system, different network addresses, combinations of these methods, or other methods, as appropriate.

An example of this type of separation is observed in web administrative interfaces that use separate authentication methods for users of any other information system resources.

This may include isolating the administrative interface on a different domain and with additional access controls.

If administrative functionality or information regarding PostgreSQL management is presented on an interface available for users, information on DBMS settings may be inadvertently made available to the user.

Check

Check PostgreSQL settings and vendor documentation to verify that administrative functionality is separate from user functionality.

As the database administrator (shown here as “postgres”), list all roles and permissions for the database:

$ sudo su - postgres $ psql -c “\du”

If any non-administrative role has the attribute “Superuser”, “Create role”, “Create DB” or “Bypass RLS”, this is a finding.

If administrator and general user functionality are not separated either physically or logically, this is a finding.

Fix

Configure PostgreSQL to separate database administration and general user functionality.

Do not grant superuser, create role, create db or bypass rls role attributes to users that do not require it.

To remove privileges, see the following example:

ALTER ROLE NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS;

Test Results

  Result
PostgreSQL query: SELECT r.rolcreatedb FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_monitor'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreaterole FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_monitor'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolsuper FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_monitor'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreatedb FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_read_all_settings'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreaterole FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_read_all_settings'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolsuper FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_read_all_settings'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreatedb FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_read_all_stats'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreaterole FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_read_all_stats'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolsuper FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_read_all_stats'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreatedb FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_stat_scan_tables'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreaterole FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_stat_scan_tables'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolsuper FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_stat_scan_tables'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreatedb FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_signal_backend'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreaterole FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_signal_backend'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolsuper FROM pg_catalog.pg_roles r WHERE r.rolname = 'pg_signal_backend'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreatedb FROM pg_catalog.pg_roles r WHERE r.rolname = 'dashboard'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreaterole FROM pg_catalog.pg_roles r WHERE r.rolname = 'dashboard'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolsuper FROM pg_catalog.pg_roles r WHERE r.rolname = 'dashboard'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreatedb FROM pg_catalog.pg_roles r WHERE r.rolname = 'replication'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreaterole FROM pg_catalog.pg_roles r WHERE r.rolname = 'replication'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolsuper FROM pg_catalog.pg_roles r WHERE r.rolname = 'replication'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreatedb FROM pg_catalog.pg_roles r WHERE r.rolname = 'haproxy'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreaterole FROM pg_catalog.pg_roles r WHERE r.rolname = 'haproxy'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolsuper FROM pg_catalog.pg_roles r WHERE r.rolname = 'haproxy'; output should not eq "t" passed
PostgreSQL query: SELECT r.rolcreatedb FROM pg_catalog.pg_roles r WHERE r.rolname = 'testuser'; output should not eq "t" failed
PostgreSQL query: SELECT r.rolcreaterole FROM pg_catalog.pg_roles r WHERE r.rolname = 'testuser'; output should not eq "t" failed
PostgreSQL query: SELECT r.rolsuper FROM pg_catalog.pg_roles r WHERE r.rolname = 'testuser'; output should not eq "t" passed

Code

control "V-72999" do

  title "PostgreSQL must separate user functionality (including user interface
services) from database management functionality."
  desc  "Information system management functionality includes functions necessary to
administer databases, network components, workstations, or servers and typically
requires privileged user access.

The separation of user functionality from information system management
functionality is either physical or logical and is accomplished by using different
computers, different central processing units, different instances of the operating
system, different network addresses, combinations of these methods, or other
methods, as appropriate.

An example of this type of separation is observed in web administrative interfaces
that use separate authentication methods for users of any other information system
resources.

This may include isolating the administrative interface on a different domain and
with additional access controls.

If administrative functionality or information regarding PostgreSQL management is
presented on an interface available for users, information on DBMS settings may be
inadvertently made available to the user."

  impact 0.5
  tag "severity": "medium"
  tag "gtitle": "SRG-APP-000211-DB-000122"
  tag "gid": "V-72999"
  tag "rid": "SV-87651r1_rule"
  tag "stig_id": "PGS9-00-008500"
  tag "cci": "CCI-001082"
  tag "nist": ["SC-2", "Rev_4"]

  tag "check": "Check PostgreSQL settings and vendor documentation to verify that
administrative functionality is separate from user functionality.

As the database administrator (shown here as \"postgres\"), list all roles and
permissions for the database:

$ sudo su - postgres
$ psql -c \"\\du\"

If any non-administrative role has the attribute \"Superuser\", \"Create role\",
\"Create DB\" or \"Bypass RLS\", this is a finding.

If administrator and general user functionality are not separated either physically
or logically, this is a finding."
  tag "fix": "Configure PostgreSQL to separate database administration and general
user functionality.

Do not grant superuser, create role, create db or bypass rls role attributes to
users that do not require it.

To remove privileges, see the following example:

ALTER ROLE <username> NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS;"

  privileges = %w(rolcreatedb rolcreaterole rolsuper)
  sql = postgres_session(PG_DBA, PG_DBA_PASSWORD, PG_HOST)

  roles_sql = 'SELECT r.rolname FROM pg_catalog.pg_roles r;'
  roles_query = sql.query(roles_sql, [PG_DB])
  roles = roles_query.lines

  roles.each do |role|
    unless PG_SUPERUSERS.include?(role)
      privileges.each do |privilege|
        privilege_sql = "SELECT r.#{privilege} FROM pg_catalog.pg_roles r "\
          "WHERE r.rolname = '#{role}';"

        describe sql.query(privilege_sql, [PG_DB]) do
          its('output') { should_not eq 't' }
        end
      end
    end
  end
end