Quantcast
Channel: Articles tagged with SQL Server - Simple Talk
Viewing all articles
Browse latest Browse all 62

Auditing SQL Server – Part 3 – SQL Server Configuration Audit

$
0
0

This is the continuation of my series on auditing SQL Server. In the first part, I discussed basic server discovery and documentation. The next section went over server hardware configuration and audits. This section gets into detailed SQL Server configuration details. This is less relevant in a cloud environment, but there are still items to confirm.

The format follows the server audit format. A general template is presented first, followed by interpreting those configuration items and ends with methods to explore and list those configurations.

General Audit Template

  • SQL Server configuration
    • Edition and patch level
    • Default file locations
      • Data
      • Log
      • Backup
      • tempdb
    • SQL Server configuration items and properties
    • Logon triggers
    • Running traces
    • Extended event sessions
    • Login model and server roles
    • SQL Agent jobs and Elastic jobs
    • Replication
    • Clustering and always-on
    • Service accounts
    • SQL Server audits
    • Query store
    • Linked servers
    • Backups
  • Environment differences
    • SQL Server configuration

Evaluating SQL Server Configuration

SQL Server configuration audit is similar to the OS evaluation with some additional details. This is the high-level check of your SQL system and it won’t apply if you are in an Azure managed instance. You need to verify the edition and patches, the backups, file locations, and other setup options.

Edition and patch level

The first, most basic check is the SQL edition and patch level. Like the OS, you want to be sure the edition is supported and the patch level is within enterprise guidelines. This is a very critical item. Security, performance, and upgrade paths are all directly impacted by the edition.

Document this and recommend an upgrade if it is getting out-of-date. Be sure it is a currently supported version. I’d also check the life cycle to ensure there is an upgrade plan before end-of-life for that version.

Default file locations

Default file location at a server level is primarily informational only. The settings that need to be interrogated thoroughly are the actual database file locations. Setting the defaults at a server level makes it more likely that individual databases will be setup correctly as they are added. The data, log, and backups should each be on separate drives. Tempdb isn’t listed with the defaults, but it should also be on a separate drive. Document the default locations and flag them if they are on same physical drive. In a cloud environment this isn’t an item that needs to be validated, and in fact, can’t be modified.

SQL Server Configuration and Properties

SQL Server has many configuration settings. My rule of thumb is to not change settings unless there is a specific reason. When looking at sever settings, pay attention to the items that are not using the default values. The primary exception for this is memory configuration. You will want to set the minimum and maximum memory for SQL Server. This can prevent memory contention with the underlying operating system.

Many of these items are important, but most shouldn’t be modified unless there is a specific, documented, reason. The main exception to this is “min server memory (MB)” and “max server memory (MB)”. It is a best practice to set the min and max to the same value. As discussed in the discovery audit, enough memory should be left for the operating system to function efficiently. The recommended value will depend on the current version of the operating system, usually be 8-12 GB.

Any other value changed from the default needs to be noted as part of the audit. There should be a reason for the change, and that reason should make sense. If the owner or the administrators of the server have changed, it may be worth investigating if the value should be reverted to the default. If you do this – be ready to quickly change it back. Each server and the associated application has a personality (SQL Server usage pattern), and hopefully the value was changed due to careful testing and planning.

New properties are added as the editions progress, so be sure to look for new values with each new version. Looking at the properties available, you can see that many don’t impact performance, but they are all useful.

Logon triggers

Logon triggers should be used sparingly and with purpose. Most servers won’t have them, so if they are present this is another item that needs to be documented and explained. They have the potential to severely alter logon behavior and reduce logon performance for the entire server. It is also possible to have multiple logon triggers. Document all logon triggers, note their purpose and document them in your audit.

You will want to work with the administrators to understand why they are present. I’m not a big fan of any trigger. They can be like an unwanted easter egg that you discover when something isn’t working as expected. They are fine if they are documented and are carefully coded. But use them with caution and make sure developers understand their behavior.

Running traces and extended events

For full SQL Server installations, you can still use traces. They will be deprecated in a future version, and Microsoft recommends moving to extended events. With that caveat, traces are still a very useful tool, commonly used. It’s good to know if any traces are running. This can give you an idea of concerns that admins have had with the server and items you may want to dig into further. It is also an area to target for potential upgrades. They don’t run on Azure SQL Database.

Extended events were created to (eventually) replace traces, along with other Azure functionality, such as audits. As with traces, it’s good to know if extended events are configured and what they are doing. Document both of these and note the events getting logged.

Login model and server roles

The login model determines if only Windows authentication can be used or SQL logins can be used in addition to Windows authentication, or various flavors of Entra IDs in Azure. In the past, the best practice was to use Windows / Integrated Authentication exclusively, when it was possible. In Azure Database, that was not an option until recently. Document the login model for the server. The team should understand the model they are using and follow best practices for that model. Managed identity is also available in Azure SQL and is considered a best practice for service accounts for other Azure resources.

The server roles granted to logins should be checked. There shouldn’t be many logins with server roles or server security directly assigned. This is especially true for the sysadmin role and control authorization at the server level. This is a critical item. List accounts with server roles and review this list with the server owners / stakeholders to be sure it is correct.

SQL Agent jobs and Elastic Jobs

On-prem servers will generally use SQL Agent jobs for maintenance tasks and other recurring database tasks. Document the jobs and look at the error logs to be sure they are running correctly. Talk with the DBA team to ensure these logs are regularly checked.

SQL Agent isn’t available in Azure SQL, but Elastic Jobs are now out of preview and can be used without concern they will be going away soon. Automated deployments, ETL, or anything else that can run TSQL can be used to run maintenance jobs in Azure, but Elastic Jobs seem like the obvious replacement.

These jobs will often run maintenance plans for on-prem servers. That will cover backups, index and statistic maintenance, and database consistency checks. In an Azure environment, you still need to maintain indexes and statistics and perform consistency checks. This can be done via Elastic jobs or other automated methods.

If you dig a little deeper into these jobs, you will want to be sure credentials aren’t stored in plain text. I have seen this multiple times at various enterprises, so be sure to check for this. Document the jobs running and their schedules. You also want to document the authentication method and accounts.

Replication

Replication can be used for a number of purposes in an enterprise, including reporting and distributed database scenarios. It is useful to know if replication is configured and the model used. This can help illuminate the security landscape and is an indication of other servers to investigate. There are also administrative tasks associated with replication. Document if the server is used as a publisher, distributor, or subscriber, administration tasks performed, and the other servers involved in replication.

Clustering and Always On

Critical servers should have some type of high-availability option configured. It might be clustering or Always On availability groups. This isn’t required, but usage should reflect the business need. If an application is deemed critical, you will want to see that reflected at the database level. Document the high-availability options used. If the server or application is listed as critical, but it doesn’t have a high-availability option configured, that is a critical item. Help the stakeholder understand the risk with a single point of failure.

Service accounts

The service accounts used for the SQL services should be documented. Remember that these accounts should follow the practice of least privilege and have the lowest possible rights to work. Refer to the Microsoft documentation linked at the bottom for specifics.

This is a critical item. The accounts should have the lowest possible privileges, at both a domain level and a machine level, while still able to run the services. I’ve seen DBAs confused by this concept, but it’s extremely critical. At a more pessimistic level, I’ve also seen elevated privileges used simply because it’s easier and less time consuming. If a bad actor gets access to the machine, they can leverage these accounts to expand access in the network. Document the service accounts and the general level of access for each of these accounts at both the machine level and network level. I would consider machine level admins a critical security item and elevated domain privileges are even more concerning.

SQL Server Audits

SQL Server audits can be used to track security related items in Azure environments. They replace some of the functionality in on-prem traces. Audits can be used to track query usage and security issues. They are not required, but if used, document their usage and the specific events logged.

Query store

Usage of the query store isn’t an issue, just an item to be noted. You may want to dig into it further and look at the queries and query plans getting stored. It can be an opportunity to adjust the data model or add indexes. Document the usage and discuss any reasons why it was configured to see if there are performance problems that need to be explored further.

Linked servers

Linked servers are another item that aren’t critical, but can have security implications and can impact cloud migrations. Linked servers aren’t supported with Azure databases, so that functionality would need to be changed to a different technology in migration scenarios. It is also possible to get elevated security to databases via linked servers. Document the linked servers and the security model used by any configured on the server.

Elastic queries are still in preview, but they have been available for several years. They can mimic some of the behavior of linked servers in Azure. Document the usage of elastic queries and work with the development teams to understand their usage.

Backups

Next, ensure that backups are happening. There may be different backup types for the various databases on a server, but backups should be configured and they should be correct for each database. This is a critical item and should be flagged if they are not happening. Understand the backup location, restore process, off-site storage and testing procedures. This is possibly the most critical item on the server and warrants thorough investigation. Technical server owners and possibly business stakeholders should be notified immediately if you confirm that backups are not configured or badly misconfigured.

Evaluating SQL Server Environment Differences

When there are multiple environments for a project, application, or set of databases, the environments at a server and SQL Server level will generally be different. The database level items should be minimal or even non-existent.

The SQL Server configuration should be very close or identical between environments. There are fewer reasons for these configurations to differ. Database jobs will differ, there may be different accounts used between environments, and different logons and authorization (different accounts for non-prod / prod, different access for developers in non-prod / prod, etc.), but the configuration items should generally match.

Performance settings, SQL Server configuration options, server and patch levels should match. Note any differences in your audit.

Gathering the SQL Audit Information

To adequately examine the SQL Server configuration requires advanced privileges. Work with your DBA team as needed.

  • Edition and patch level
  • Default file locations
  • Configuration items not set to default
  • Additional server settings
  • Logon triggers
  • Default traces
  • Extended event sessions
  • Login model and settings
  • Replication
  • Service accounts
  • Query store

SQL Server Edition and Patch Level

One of the easiest and most important items to check is the server version. You will get different information back depending on the type of server deployment. I showed this in the server audit, but I’ll show it again here.

SELECT @@VERSION

This will show the current edition and patch level.

Default file locations

The following works with SQL Server 2019 and higher. For previous versions, use SSMS or interrogate the registry for the default backup path location.

SELECT 
	SERVERPROPERTY('InstanceDefaultDataPath')		DefaultDataPath
	,SERVERPROPERTY('InstanceDefaultLogPath')		DefaultLogPath
	,SERVERPROPERTY('InstanceDefaultBackupPath')	DefaultBackupPath

With traditional physical disks, the data, log and backup paths should be on separate drives. Even with more advanced drive types it can be useful for these to be separated so the drive subsystem isn’t overloaded. Having the defaults set correctly at the server level helps with database configuration.

SQL Server Configuration

Most configurable server items are managed via SSMS or sp_configure. Running sp_configure will also show how these items are configured. Pay attention to the items that are not using the default values. You will want to be sure you have enabled “show advanced options” so you don’t miss anything. This command isn’t available in Azure SQL.

--Advanced options only needs to be set once. It, and reconfigure, can be skipped after it is set.
EXEC sp_configure 'show advanced options',1
GO
RECONFIGURE
GO
EXEC sp_configure
GO

Another, possibly better, option for looking at server-wide configuration settings is sys.configurations. This works in Azure as well as on-prem servers and it shows all configuration values without any switches needing to be enabled. It’s a newer option and doesn’t allow changing the values. Old habits die hard, so I’m still more likely to use sp_configure first, but sys.configurations is easier and more flexible in some ways.

SELECT *
FROM sys.configurations

SQL Server Properties

Many valuable server configuration settings are available via the function SERVERPROPERTY. The following will show these properties. These settings will help the overall picture of your audit, especially when compared to other servers in the enterprise. Be sure to any new options that become available as new editions are released.

DECLARE @Properties TABLE (
	PropertyName		varchar(255)
)
INSERT INTO @Properties (
	PropertyName
)
VALUES 
	('BuildClrVersion')
	,('Collation')
	,('CollationID')
	,('ComparisonStyle')
	,('ComputerNamePhysicalNetBIOS')
	,('Edition')
	,('EditionID')
	,('EngineEdition')
	,('FilestreamConfiguredLevel')
	,('FilestreamEffectiveLevel')
	,('FilestreamShareName')
	,('HadrManagerStatus')
	,('InstanceDefaultBackupPath')
	,('InstanceDefaultDataPath')
	,('InstanceDefaultLogPath')
	,('InstanceName')
	,('IsAdvancedAnalyticsInstalled')
	,('IsBigDataCluster')
	,('IsClustered')
	,('IsExternalAuthenticationOnly')
	,('IsExternalGovernanceEnabled')
	,('IsFullTextInstalled')
	,('IsHadrEnabled')
	,('IsIntegratedSecurityOnly')
	,('IsLocalDB')
	,('IsPolybaseInstalled')
	,('IsServerSuspendedForSnapshotBackup')
	,('IsSingleUser')
	,('IsTempDbMetadataMemoryOptimized')
	,('IsXTPSupported')
	,('LCID')
	,('LicenseType')
	,('MachineName')
	,('NumLicenses')
	,('PathSeparator')
	,('ProcessID')
	,('ProductBuild')
	,('ProductBuildType')
	,('ProductLevel')
	,('ProductMajorVersion')
	,('ProductMinorVersion')
	,('ProductUpdateLevel')
	,('ProductUpdateReference')
	,('ProductUpdateType')
	,('ProductVersion')
	,('ResourceLastUpdateDateTime')
	,('ResourceVersion')
	,('ServerName')
	,('SqlCharSet')
	,('SqlCharSetName')
	,('SqlSortOrder')
	,('SqlSortOrderName')
	,('SuspendedDatabaseCount')
SELECT
	@@SERVERNAME	ServerName
	,PropertyName
	,SERVERPROPERTY(PropertyName) PropertyValue
FROM @Properties

Logon triggers

The following can be used to find logon triggers. Remember that there can be more than one logon trigger defined.

SELECT *
FROM sys.server_triggers ST
	INNER JOIN sys.server_trigger_events STE
		ON ST.object_id		= STE.object_id

Running traces

Traces that are configured and running will be shown with the following.

SELECT traceid,property,value
FROM ::fn_trace_getinfo(0)
WHERE property = 5

If you get any rows back, as shown above, you will want to see what events are getting logged and why the trace is running.

Extended events

You can check running extended events on a server using the following.

SELECT *
FROM sys.server_event_sessions

In Azure SQL Database, you can use the following.

SELECT *
FROM sys.database_event_sessions

These will both show you the event sessions running in the given context. As with traces, understand why they are running and the events getting logged.

Login model

The easiest way to look at this is via the properties of the server in SSMS. I checked the SQL used by SSMS, and the value is stored in a registry key, so you can also run a query to obtain the login model.

exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'LoginMode'

1 is Windows authentication, and 2 is mixed authentication.

Server roles

Server level roles should be very limited.

SELECT
	@@SERVERNAME						ServerName
	,SP.name							LoginName
	,SP.type							LoginType
	,SP.type_desc						LoginTypeDescription
	,SP.is_disabled						LoginIsDisabled
	,SP.default_database_name			LoginDefaultDatabaseName
	,SP.default_language_name			LoginDefaultLanguageName
	,ROL.name							RoleName
	,ROL.type							RoleType
	,ROL.type_desc						RoleTypeDescription
	,ROL.is_disabled					RoleIsDisabled
	,CONVERT(date,GETDATE())			ReportDate
FROM master.sys.server_role_members SRM
	INNER JOIN master.sys.server_principals SP
		ON SRM.member_principal_id			= SP.principal_id
	INNER JOIN master.sys.server_principals ROL
		ON SRM.role_principal_id			= ROL.principal_id

Permissions assigned directly to logins should also be very limited. Pay special attention to high security permissions such as CONTROL. Review the permission chart for specific details.

SELECT
	SP.class
	,SP.class_desc
	,SP.major_id
	,SP.minor_id
	,GRE.name			GranteeName
	,GRE.is_disabled	GranteeIsDisabled
	,GRO.name			GrantorName
	,SP.type			PermissionType
	,SP.permission_name
	,SP.state
	,SP.state_desc
FROM sys.server_permissions SP
	INNER JOIN sys.server_principals GRE
		ON SP.grantee_principal_id		= GRE.principal_id
	INNER JOIN sys.server_principals GRO
		ON SP.grantor_principal_id		= GRO.principal_id
WHERE GRE.is_disabled					= 0
ORDER BY 
	GRE.name
	,SP.class_desc
	,SP.permission_name

SQL Jobs and Elastic Jobs

The following shows all SQL jobs, with step details in an XML list and the command run by the job.

SELECT
	@@SERVERNAME			ServerName
	,GETDATE()				ReportDate
	,sj.name				JobName
	,sj.date_created
	,sj.date_modified
	,sj.job_id				JobId
	,sj.enabled				JobEnabled
	,'SQL Server Agent Job' JobLocation
	,sl.name Owner
	,sl.name ExecuteAs
	,stp.step_id
	,stp.step_name
	,stp.subsystem
	,stp.Command
	,(SELECT CONVERT(xml,'<root>' + (SELECT stp1.step_name, Command, database_name, output_file_name FROM msdb.dbo.sysjobsteps stp1 WHERE stp1.job_id = sj.job_id AND STP1.step_id = stp.step_id FOR XML PATH('')) + '</root>')) StepDetails
	,stp.database_name
	,stp.output_file_name 
	,sjs.schedule_id
	,ss.name ScheduleName
	,ss.enabled				ScheduleEnabled
	,sjs.next_run_date
	,sjs.next_run_time
	,CASE ss.freq_type
		WHEN 1 THEN 'Once'
		WHEN 4 THEN 'Daily'
		WHEN 8 THEN 'Weekly'
		WHEN 16 THEN 'Monthly'
		WHEN 32 THEN 'Monthly, relative to freq_interval'
		WHEN 64 THEN 'Run when SQLServerAgent service starts'
		WHEN 128 THEN 'Run when the computer is idle'
	END freq_type
	,CASE ss.freq_type
			WHEN 4 THEN 'Every ' + CONVERT(varchar(3),freq_interval) + ' days'
			WHEN 8 THEN 'Weekly'
			WHEN 16 THEN 'On the ' + CONVERT(varchar(2),freq_interval) + ' of the month'
			WHEN 32 THEN CASE freq_interval
							WHEN 1 THEN 'Sunday'
							WHEN 2 THEN 'Monday'
							WHEN 3 THEN 'Tuesday'
							WHEN 4 THEN 'Wednesday'
							WHEN 5 THEN 'Thursday'
							WHEN 6 THEN 'Friday'
							WHEN 7 THEN 'Saturday'
							WHEN 8 THEN 'Day'
							WHEN 9 THEN 'Weekday'
							WHEN 10 THEN 'Weekend day'
						END
		END freq_interval
FROM msdb.dbo.sysjobs sj
	LEFT JOIN msdb.dbo.sysjobsteps stp
		ON sj.job_id = stp.job_id
	LEFT JOIN msdb.dbo.sysjobschedules sjs
		ON sj.job_id = sjs.job_id
	LEFT JOIN msdb.dbo.sysschedules ss 
		ON sjs.schedule_id = ss.schedule_id 
	LEFT JOIN master.dbo.syslogins sl
		ON sj.owner_sid = sid
ORDER BY 
	sj.name
	,ss.name
GO

The following was taken from Microsoft and shows the current jobs and steps in an Elastic Job Server. These can also be created and managed using PowerShell or the Azure portal.

SELECT 
	J.*
	,JS.* 
FROM jobs.jobs J
	INNER JOIN jobs.jobsteps JS
		ON J.job_id = JS.job_id 
		AND J.job_version = JS.job_version
GO

Replication

Replication status can be verified and monitored in SSMS.

Each database can be checked for replication information with the following. Replication is a large topic and beyond the scope of this audit. Refer to the Microsoft documentation for additional monitoring scripts. For the SQL configuration audit, it is sufficient to know if the server is used in replication.

SELECT
	DATABASEPROPERTYEX(DB_NAME(),'IsPublished')
	,DATABASEPROPERTYEX(DB_NAME(),'IsMergePublished')
	,DATABASEPROPERTYEX(DB_NAME(),'IsSubscribed')
	,DATABASEPROPERTYEX(DB_NAME(),'ReplicaID')

Cluster / Always-on

If a server is clustered, it will be shown in the server properties.

SELECT 
	SERVERPROPERTY('IsClustered') IsClustered

Always-on high availability setup is shown with the following script.

SELECT 
	hags.primary_replica 
	,hags.primary_recovery_health
	,hags.primary_recovery_health_desc
	,hags.secondary_recovery_health
	,hags.secondary_recovery_health_desc
	,hags.synchronization_health
	,hags.synchronization_health_desc
FROM sys.dm_hadr_availability_group_states hags
	INNER JOIN sys.availability_groups ag 
		ON ag.group_id = hags.group_id

Service Accounts

Service accounts for a server installation can be found with the following.

SELECT *
FROM sys.dm_server_services

SQL Server Audits

SQL Server audits are shown with the following query.

SELECT *
FROM sys.dm_server_audit_status

The Azure portal can also be used to show the audits.

Query Store

If the query store is used, the following can be used to examine the queries configured and stored.

SELECT *
FROM sys.query_store_query QSQ
	INNER JOIN sys.query_store_query_text QST
		ON QSQ.query_text_id			= QST.query_text_id

Linked Servers

This will show the configured linked servers. Note that it will also show the local server.

SELECT *
FROM sys.servers

The following was taken from SSMS and shows the configured linked servers and the associated login methods.

SELECT
	srv.name LinkedServerName
	,srv.data_source
	,srv.provider
	,ll.remote_name AS [RemoteUser]
	,CAST(ll.uses_self_credential AS bit) AS [Impersonate]
	,ll.modify_date AS [DateLastModified]
FROM sys.servers AS srv
	INNER JOIN sys.linked_logins ll 
		ON ll.server_id=CAST(srv.server_id AS int)
	LEFT OUTER JOIN sys.server_principals sp 
		ON ll.local_principal_id = sp.principal_id
GO

Backups

Backup history can be accessed with the following.

SELECT
	BS.Database_name
	,BS.type
	,CASE BS.type
		WHEN 'D' THEN 'Database'
		WHEN 'I' THEN 'Differential database'
		WHEN 'L' THEN 'Log'
		WHEN 'F' THEN 'File or filegroup'
		WHEN 'G' THEN 'Differential file'
		WHEN 'P' THEN 'Partial'
		WHEN 'Q' THEN 'Differential partial'
	END BackupType
	,BS.user_name
	,BS.first_lsn
	,BS.last_lsn
	,BS.backup_start_date
	,BS.backup_finish_date
	,BS.server_name
	,BS.compressed_backup_size
	,BMF.physical_device_name
	,ROW_NUMBER() OVER(PARTITION BY BS.database_name, BS.type ORDER BY BS.database_name, BS.type, BS.backup_start_date DESC) SELECT_CRITERIA
FROM msdb.dbo.backupset BS
	INNER JOIN msdb.dbo.backupmediaset BMS
		ON BS.media_set_id				= BMS.media_set_id
	INNER JOIN msdb.dbo.backupmediafamily BMF
		ON BS.media_set_id				= BMF.media_set_id

Azure backup history is accessed via a different DMV.

SELECT *
FROM sys.dm_database_backups

Summary

SQL Server configuration audits can be quite extensive. There is always another rock to turn over when doing an audit of this nature, so it’s important to have a plan before you begin. Key items are backups, any configuration item not set to the default, security related items, and high-availability options. Work with your team on any critical items so they can be addresses as early as possible.

References

The post Auditing SQL Server – Part 3 – SQL Server Configuration Audit appeared first on Simple Talk.


Viewing all articles
Browse latest Browse all 62

Trending Articles