Added PostgreSQL rules and updates #49 #50 #51 (#52)

- Added rule to check if allow access to Azure services enabled for PostgreSQL. #50
- Added rule to count the number of database server firewall rules for PostgreSQL. #51
- Added rule to check if SSL is enforced for PostgreSQL. #49
This commit is contained in:
Bernie White 2019-06-12 11:55:39 +10:00 коммит произвёл GitHub
Родитель a32a2dd522
Коммит 62846d2433
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
14 изменённых файлов: 421 добавлений и 22 удалений

Просмотреть файл

@ -3,6 +3,9 @@
- Added rule to check if allow access to Azure services enabled for MySQL. [#4](https://github.com/BernieWhite/PSRule.Rules.Azure/issues/4)
- Added rule to count the number of database server firewall rules for MySQL. [#2](https://github.com/BernieWhite/PSRule.Rules.Azure/issues/2)
- Added rule to check if allow access to Azure services enabled for PostgreSQL. [#50](https://github.com/BernieWhite/PSRule.Rules.Azure/issues/50)
- Added rule to count the number of database server firewall rules for PostgreSQL. [#51](https://github.com/BernieWhite/PSRule.Rules.Azure/issues/51)
- Added rule to check if SSL is enforced for PostgreSQL. [#49](https://github.com/BernieWhite/PSRule.Rules.Azure/issues/49)
## v0.1.0-B190607 (pre-release)

Просмотреть файл

@ -8,12 +8,20 @@ online version: https://github.com/BernieWhite/PSRule.Rules.Azure/blob/master/do
## SYNOPSIS
Use encrypted MySQL connections.
Enforce encrypted MySQL connections.
## DESCRIPTION
Use encrypted MySQL connections.
Azure Database for MySQL is configured to accept unencrypted connections. Unencrypted connections are disabled by default.
Unencrypted communication to MySQL server instances could allow disclosure of information to an untrusted party.
## RECOMMENDATION
Use encrypted MySQL connections.
Azure Database for MySQL should be configured to only accept encrypted connections.
When enforce SSL connections is disabled, encrypted and unencrypted connections are permitted. To prevent unencrypted connections, enable SSL connection enforcement.
Unless explicitly required, consider enabling SSL connection enforcement.
For more information see [SSL connectivity in Azure Database for MySQL](https://docs.microsoft.com/en-us/azure/mysql/concepts-ssl-connection-security)

Просмотреть файл

@ -0,0 +1,25 @@
---
severity: Important
category: Security configuration
online version: https://github.com/BernieWhite/PSRule.Rules.Azure/blob/master/docs/rules/en-US/Azure.PostgreSQL.AllowAzureAccess.md
---
# Azure.PostgreSQL.AllowAzureAccess
## SYNOPSIS
Determine if access from Azure services is required.
## DESCRIPTION
Allow access to Azure services, permits any Azure service including other Azure customers, network based access to databases on the same PostgreSQL server instance.
If network based access is permitted, authentication is still required.
Enabling access from Azure Services is useful in certain cases for on demand PaaS workloads where configuring a stable IP address is not possible. For example Azure Functions, Container Instances and Logic Apps.
## RECOMMENDATION
Where a stable IP addresses are able to be configured, configure IP or virtual network based firewall rules instead of using Allow access to Azure services.
Determine if access from Azure services is required for the services connecting to the hosted databases.

Просмотреть файл

@ -0,0 +1,19 @@
---
severity: Awareness
category: Operations management
online version: https://github.com/BernieWhite/PSRule.Rules.Azure/blob/master/docs/rules/en-US/Azure.PostgreSQL.FirewallRuleCount.md
---
# Azure.PostgreSQL.FirewallRuleCount
## SYNOPSIS
Determine if there is an excessive number of firewall rules.
## DESCRIPTION
Typically number of firewall rules required is minimal, with management connectivity from on-premises and cloud application connectivity the most common.
## RECOMMENDATION
PostgreSQL Server has greater then ten (10) firewall rules. Some rules may not be needed.

Просмотреть файл

@ -0,0 +1,27 @@
---
severity: Critical
category: Security configuration
online version: https://github.com/BernieWhite/PSRule.Rules.Azure/blob/master/docs/rules/en-US/Azure.PostgreSQL.UseSSL.md
---
# Azure.PostgreSQL.UseSSL
## SYNOPSIS
Enforce encrypted PostgreSQL connections.
## DESCRIPTION
Azure Database for PostgreSQL is configured to accept unencrypted connections. Unencrypted connections are disabled by default.
Unencrypted communication to PostgreSQL server instances could allow disclosure of information to an untrusted party.
## RECOMMENDATION
Azure Database for PostgreSQL should be configured to only accept encrypted connections.
When enforce SSL connections is disabled, encrypted and unencrypted connections are permitted. To prevent unencrypted connections, enable SSL connection enforcement.
Unless explicitly required, consider enabling SSL connection enforcement.
For more information see [Configure SSL connectivity in Azure Database for PostgreSQL](https://docs.microsoft.com/en-us/azure/postgresql/concepts-ssl-connection-security)

Просмотреть файл

@ -16,8 +16,6 @@ Azure Redis Cache is configured to accept unencrypted connections using a non-SS
Unencrypted communication to Redis Cache could allow disclosure of information to an untrusted party.
This does not indicate that unencrypted connections are being used.
## RECOMMENDATION
Azure Redis Cache should be configured to only accept secure connections.

Просмотреть файл

@ -11,10 +11,11 @@ The following modules are required for `PSRule.Rules.Azure` to work:
- PSRule
- Az.Accounts
- Az.Resources
- Az.Security
- Az.Sql
- Az.Storage
- Az.Websites
- Az.Sql
The required version of each module will automatically be installed along-side `PSRule.Rules.Azure` when using `Install-Module` or `Update-Module` cmdlets.

Просмотреть файл

@ -168,23 +168,23 @@ task platyPS {
# Synopsis: Install module dependencies
task ModuleDependencies NuGet, PSRule, {
if ($Null -eq (Get-InstalledModule -Name Az.Accounts -ErrorAction Ignore)) {
Install-Module -Name Az.Accounts -Scope CurrentUser -Force;
if ($Null -eq (Get-InstalledModule -Name Az.Accounts -MinimumVersion 1.5.2 -ErrorAction Ignore)) {
Install-Module -Name Az.Accounts -Scope CurrentUser -MinimumVersion 1.5.2 -Force;
}
if ($Null -eq (Get-InstalledModule -Name Az.Resources -ErrorAction Ignore)) {
Install-Module -Name Az.Resources -Scope CurrentUser -Force;
if ($Null -eq (Get-InstalledModule -Name Az.Resources -MinimumVersion 1.4.0 -ErrorAction Ignore)) {
Install-Module -Name Az.Resources -Scope CurrentUser -MinimumVersion 1.4.0 -Force;
}
if ($Null -eq (Get-InstalledModule -Name Az.Storage -ErrorAction Ignore)) {
Install-Module -Name Az.Storage -Scope CurrentUser -Force -AllowClobber;
if ($Null -eq (Get-InstalledModule -Name Az.Security -MinimumVersion 0.7.4 -ErrorAction Ignore)) {
Install-Module -Name Az.Security -Scope CurrentUser -MinimumVersion 0.7.4 -Force;
}
if ($Null -eq (Get-InstalledModule -Name Az.Security -ErrorAction Ignore)) {
Install-Module -Name Az.Security -Scope CurrentUser -Force;
if ($Null -eq (Get-InstalledModule -Name Az.Storage -MinimumVersion 1.3.0 -ErrorAction Ignore)) {
Install-Module -Name Az.Storage -Scope CurrentUser -MinimumVersion 1.3.0 -Force -AllowClobber;
}
if ($Null -eq (Get-InstalledModule -Name Az.Sql -ErrorAction Ignore)) {
Install-Module -Name Az.Sql -Scope CurrentUser -Force;
if ($Null -eq (Get-InstalledModule -Name Az.Sql -MinimumVersion 1.9.0 -ErrorAction Ignore)) {
Install-Module -Name Az.Sql -Scope CurrentUser -MinimumVersion 1.9.0 -Force;
}
if ($Null -eq (Get-InstalledModule -Name Az.Websites -ErrorAction Ignore)) {
Install-Module -Name Az.Websites -Scope CurrentUser -Force;
if ($Null -eq (Get-InstalledModule -Name Az.Websites -MinimumVersion 1.2.1 -ErrorAction Ignore)) {
Install-Module -Name Az.Websites -Scope CurrentUser -MinimumVersion 1.2.1 -Force;
}
}
@ -241,8 +241,10 @@ task BuildHelp BuildModule, PlatyPS, {
# Copy generated help into module out path
$Null = Copy-Item -Path out/docs/PSRule.Rules.Azure/ -Destination out/modules/PSRule.Rules.Azure/en-US/ -Recurse;
$Null = Copy-Item -Path out/docs/PSRule.Rules.Azure/ -Destination out/modules/PSRule.Rules.Azure/en-AU/ -Recurse;
$Null = Copy-Item -Path out/docs/PSRule.Rules.Azure/ -Destination out/modules/PSRule.Rules.Azure/en-GB/ -Recurse;
$Null = Copy-Item -Path docs/rules/en-US/*.md -Destination out/modules/PSRule.Rules.Azure/en-US/;
$Null = Copy-Item -Path docs/rules/en-US/*.md -Destination out/modules/PSRule.Rules.Azure/en-AU/;
$Null = Copy-Item -Path docs/rules/en-US/*.md -Destination out/modules/PSRule.Rules.Azure/en-GB/;
}
task ScaffoldHelp Build, BuildRuleDocs, {

Просмотреть файл

@ -51,6 +51,7 @@ DotNetFrameworkVersion = '4.7.2'
RequiredModules = @(
@{ ModuleName = 'PSRule'; ModuleVersion = '0.0.1' }
@{ ModuleName = 'Az.Accounts'; ModuleVersion = '1.5.2' }
@{ ModuleName = 'Az.Resources'; ModuleVersion = '1.4.0' }
@{ ModuleName = 'Az.Security'; ModuleVersion = '0.7.4' }
@{ ModuleName = 'Az.Storage'; ModuleVersion = '1.3.0' }
@{ ModuleName = 'Az.Sql'; ModuleVersion = '1.9.0' }

Просмотреть файл

@ -9,7 +9,7 @@ Rule 'Azure.MySQL.UseSSL' -If { ResourceType 'Microsoft.DBforMySQL/servers' } -T
# Synopsis: Determine if there is an excessive number of firewall rules
Rule 'Azure.MySQL.FirewallRuleCount' -If { ResourceType 'Microsoft.DBforMySQL/servers' } -Tag @{ severity = 'Awareness'; category = 'Operations management' } {
Hint 'SQL Server has > 10 firewall rules, some rules may not be needed';
Hint 'MySQL Server has > 10 firewall rules, some rules may not be needed';
$firewallRules = @($TargetObject.resources | Where-Object -FilterScript {
$_.Type -eq 'Microsoft.DBforMySQL/servers/firewallRules'

Просмотреть файл

@ -0,0 +1,30 @@
#
# Validation rules for Azure Database for PostgreSQL
#
# Synopsis: Use encrypted PostgreSQL connections
Rule 'Azure.PostgreSQL.UseSSL' -If { ResourceType 'Microsoft.DBforPostgreSQL/servers' } -Tag @{ severity = 'Critical'; category = 'Security configuration' } {
Within 'Properties.sslEnforcement' 'Enabled'
}
# Synopsis: Determine if there is an excessive number of firewall rules
Rule 'Azure.PostgreSQL.FirewallRuleCount' -If { ResourceType 'Microsoft.DBforPostgreSQL/servers' } -Tag @{ severity = 'Awareness'; category = 'Operations management' } {
Hint 'PostgreSQL Server has > 10 firewall rules, some rules may not be needed';
$firewallRules = @($TargetObject.resources | Where-Object -FilterScript {
$_.Type -eq 'Microsoft.DBforPostgreSQL/servers/firewallRules'
})
$firewallRules.Length -le 10;
}
# Synopsis: Determine if access from Azure services is required
Rule 'Azure.PostgreSQL.AllowAzureAccess' -If { ResourceType 'Microsoft.DBforPostgreSQL/servers' } -Tag @{ severity = 'Important'; category = 'Security configuration' } {
$firewallRules = @($TargetObject.resources | Where-Object -FilterScript {
$_.Type -eq 'Microsoft.DBforPostgreSQL/servers/firewallRules' -and
(
$_.ResourceName -eq 'AllowAllWindowsAzureIps' -or
($_.properties.startIpAddress -eq '0.0.0.0' -and $_.properties.endIpAddress -eq '0.0.0.0')
)
})
$firewallRules.Length -eq 0;
}

Просмотреть файл

@ -1,5 +1,5 @@
#
# Unit tests for Azure Database for MySql rules
# Unit tests for Azure Database for MySQL rules
#
[CmdletBinding()]
@ -26,8 +26,8 @@ Describe 'Azure.MySQL' {
Context 'Conditions' {
$result = Invoke-PSRule -Module PSRule.Rules.Azure -InputPath $dataPath -WarningAction Ignore;
It 'Azure.MySql.UseSSL' {
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.MySql.UseSSL' };
It 'Azure.MySQL.UseSSL' {
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.MySQL.UseSSL' };
# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });

Просмотреть файл

@ -0,0 +1,77 @@
#
# Unit tests for Azure Database for PostgreSQL rules
#
[CmdletBinding()]
param (
)
# Setup error handling
$ErrorActionPreference = 'Stop';
Set-StrictMode -Version latest;
if ($Env:SYSTEM_DEBUG -eq 'true') {
$VerbosePreference = 'Continue';
}
# Setup tests paths
$rootPath = $PWD;
Import-Module (Join-Path -Path $rootPath -ChildPath out/modules/PSRule.Rules.Azure) -Force;
$here = (Resolve-Path $PSScriptRoot).Path;
Describe 'Azure.PostgreSQL' {
$dataPath = Join-Path -Path $here -ChildPath 'Resources.PostgreSQL.json';
Context 'Conditions' {
$result = Invoke-PSRule -Module PSRule.Rules.Azure -InputPath $dataPath -WarningAction Ignore;
It 'Azure.PostgreSQL.UseSSL' {
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.PostgreSQL.UseSSL' };
# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'server-B';
# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'server-A';
}
It 'Azure.PostgreSQL.FirewallRuleCount' {
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.PostgreSQL.FirewallRuleCount' };
# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'server-B';
# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'server-A';
}
It 'Azure.PostgreSQL.AllowAzureAccess' {
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.PostgreSQL.AllowAzureAccess' };
# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'server-B';
# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'server-A';
}
}
}

Просмотреть файл

@ -0,0 +1,208 @@
[
{
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.DBforPostgreSQL/servers/server-B",
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.DBforPostgreSQL/servers/server-B",
"Location": "region",
"ResourceName": "server-B",
"Name": "server-B",
"Properties": {
"administratorLogin": "dbadmin",
"storageProfile": {
"storageMB": 102400,
"backupRetentionDays": 7,
"geoRedundantBackup": "Disabled",
"storageAutoGrow": "Enabled"
},
"version": "10",
"sslEnforcement": "Disabled",
"userVisibleState": "Ready",
"fullyQualifiedDomainName": "server-B.postgres.database.azure.com",
"replicationRole": "None",
"masterServerId": "",
"replicaCapacity": 5
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers",
"ResourceType": "Microsoft.DBforPostgreSQL/servers",
"Sku": {
"Name": "GP_Gen5_4",
"Tier": "GeneralPurpose",
"Size": null,
"Family": "Gen5",
"Model": null,
"Capacity": 4
},
"Tags": null,
"SubscriptionId": "00000000-0000-0000-0000-000000000000",
"resources": [
{
"ResourceName": "AllowAllWindowsAzureIps",
"Name": "AllowAllWindowsAzureIps",
"Properties": {
"startIpAddress": "0.0.0.0",
"endIpAddress": "0.0.0.0"
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"ResourceType": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
},
{
"ResourceName": "ClientIPAddress_1",
"Name": "ClientIPAddress_1",
"Properties": {
"startIpAddress": "10.1.1.1",
"endIpAddress": "10.1.1.1"
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"ResourceType": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
},
{
"ResourceName": "ClientIPAddress_2",
"Name": "ClientIPAddress_2",
"Properties": {
"startIpAddress": "10.1.2.1",
"endIpAddress": "10.1.2.1"
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"ResourceType": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
},
{
"ResourceName": "ClientIPAddress_3",
"Name": "ClientIPAddress_3",
"Properties": {
"startIpAddress": "10.1.3.1",
"endIpAddress": "10.1.3.1"
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"ResourceType": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
},
{
"ResourceName": "ClientIPAddress_4",
"Name": "ClientIPAddress_4",
"Properties": {
"startIpAddress": "10.1.4.1",
"endIpAddress": "10.1.4.1"
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"ResourceType": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
},
{
"ResourceName": "ClientIPAddress_5",
"Name": "ClientIPAddress_5",
"Properties": {
"startIpAddress": "10.1.5.1",
"endIpAddress": "10.1.5.1"
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"ResourceType": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
},
{
"ResourceName": "ClientIPAddress_6",
"Name": "ClientIPAddress_6",
"Properties": {
"startIpAddress": "10.1.6.1",
"endIpAddress": "10.1.6.1"
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"ResourceType": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
},
{
"ResourceName": "ClientIPAddress_7",
"Name": "ClientIPAddress_7",
"Properties": {
"startIpAddress": "10.1.7.1",
"endIpAddress": "10.1.7.1"
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"ResourceType": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
},
{
"ResourceName": "ClientIPAddress_8",
"Name": "ClientIPAddress_8",
"Properties": {
"startIpAddress": "10.1.8.1",
"endIpAddress": "10.1.8.1"
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"ResourceType": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
},
{
"ResourceName": "ClientIPAddress_9",
"Name": "ClientIPAddress_9",
"Properties": {
"startIpAddress": "10.1.9.1",
"endIpAddress": "10.1.9.1"
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"ResourceType": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
},
{
"ResourceName": "ClientIPAddress_10",
"Name": "ClientIPAddress_10",
"Properties": {
"startIpAddress": "10.1.10.1",
"endIpAddress": "10.1.10.1"
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"ResourceType": "Microsoft.DBforPostgreSQL/servers/firewallRules",
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
}
]
},
{
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.DBforPostgreSQL/servers/server-A",
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.DBforPostgreSQL/servers/server-A",
"Location": "region",
"ResourceName": "server-A",
"Name": "server-A",
"Properties": {
"administratorLogin": "dbadmin",
"storageProfile": {
"storageMB": 102400,
"backupRetentionDays": 7,
"geoRedundantBackup": "Disabled",
"storageAutoGrow": "Enabled"
},
"version": "10",
"sslEnforcement": "Enabled",
"userVisibleState": "Ready",
"fullyQualifiedDomainName": "server-A.postgres.database.azure.com",
"replicationRole": "None",
"masterServerId": "",
"replicaCapacity": 5
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DBforPostgreSQL/servers",
"ResourceType": "Microsoft.DBforPostgreSQL/servers",
"Sku": {
"Name": "GP_Gen5_4",
"Tier": "GeneralPurpose",
"Size": null,
"Family": "Gen5",
"Model": null,
"Capacity": 4
},
"Tags": null,
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
}
]