Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(new): Added Azure.Cosmos.DisableLocalAuth #2862

Merged
2 changes: 2 additions & 0 deletions docs/CHANGELOG-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers

- New rules:
- Cosmos DB:
- Check that database accounts have local authentication disabled by @BenjaminEngeset.
[#2846](https://github.com/Azure/PSRule.Rules.Azure/issues/2846)
- Check that database accounts have public network access disabled by @BenjaminEngeset.
[#2702](https://github.com/Azure/PSRule.Rules.Azure/issues/2702)

Expand Down
102 changes: 102 additions & 0 deletions docs/en/rules/Azure.Cosmos.DisableLocalAuth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
severity: Critical
pillar: Security
category: SE:05 Identity and access
resource: Cosmos DB
online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.Cosmos.DisableLocalAuth/
---

# Disable local authentication on Cosmos DB

## SYNOPSIS

Azure Cosmos DB should have local authentication disabled.

## DESCRIPTION

Every request to an Cosmos DB Account resource must be authenticated.
Cosmos DB supports authenticating requests using either Entra ID (previously Azure AD) identities or local authentication.
Local authentication uses accounts keys that are granted permissions to the entire Cosmos DB Account.

Using Entra ID, provides consistency as a single authoritative source which:

- Increases clarity and reduces security risks from human errors and configuration complexity.
- Allows granting of permissions using role-based access control (RBAC).
- Provides support for advanced identity security and governance features.

Disabling local authentication ensures that Entra ID is used exclusively for authentication.
Any subsequent requests to the resource using account keys will be rejected.

## RECOMMENDATION

Consider disabling local authentication on Cosmos DB.

## EXAMPLES

### Configure with Azure template

To deploy database accounts that pass this rule:

- Set the `properties.disableLocalAuth` property to `true`.

For example:

```json
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"apiVersion": "2023-11-15",
"name": "[parameters('name')]",
"location": "[parameters('location')]",
"kind": "GlobalDocumentDB",
"properties": {
"disableLocalAuth": true,
"locations": [
{
"locationName": "[parameters('location')]",
"failoverPriority": 0,
"isZoneRedundant": true
}
]
}
}
```

### Configure with Bicep

To deploy database accounts that pass this rule:

- Set the `properties.disableLocalAuth` property to `true`.

For example:

```bicep
resource account 'Microsoft.DocumentDB/databaseAccounts@2023-11-15' = {
name: name
location: location
kind: 'GlobalDocumentDB'
properties: {
disableLocalAuth: true
locations: [
{
locationName: location
failoverPriority: 0
isZoneRedundant: true
}
]
}
}
```

## NOTES

Enforcing role-based access control as the only authentication method is currently only supported for the `NoSQL API`.

## LINKS

- [SE:05 Identity and access management](https://learn.microsoft.com/azure/well-architected/security/design-identity-authentication)
- [Enforcing role-based access control as the only authentication method](https://learn.microsoft.com/azure/cosmos-db/how-to-setup-rbac#disable-local-auth)
- [Configure role-based access control with Microsoft Entra ID for your Azure Cosmos DB account management plane](https://learn.microsoft.com/azure/cosmos-db/role-based-access-control)
- [Configure role-based access control with Microsoft Entra ID for your Azure Cosmos DB account data plane](https://learn.microsoft.com/azure/cosmos-db/how-to-setup-rbac)
- [Azure security baseline for Azure Cosmos DB](https://learn.microsoft.com/security/benchmark/azure/baselines/azure-cosmos-db-security-baseline)
- [IM-1: Use centralized identity and authentication system](https://learn.microsoft.com/security/benchmark/azure/baselines/azure-cosmos-db-security-baseline#im-1-use-centralized-identity-and-authentication-system)
- [Azure deployment reference](https://learn.microsoft.com/azure/templates/microsoft.documentdb/databaseaccounts)
23 changes: 15 additions & 8 deletions src/PSRule.Rules.Azure/rules/Azure.Cosmos.Rule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,31 @@
#region Rules

# Synopsis: Enable Microsoft Defender for Azure Cosmos DB.
Rule 'Azure.Cosmos.DefenderCloud' -Ref 'AZR-000382' -Type 'Microsoft.DocumentDb/databaseAccounts' -If { $Configuration.AZURE_COSMOS_DEFENDER_PER_ACCOUNT -and (IsNoSQL) } -Tag @{ release = 'GA'; ruleSet = '2023_06'; 'Azure.WAF/pillar' = 'Security'; } -Labels @{ 'Azure.MCSB.v1/control' = 'DP-2', 'LT-1' } {
Rule 'Azure.Cosmos.DefenderCloud' -Ref 'AZR-000382' -Type 'Microsoft.DocumentDb/databaseAccounts' -If { $Configuration.AZURE_COSMOS_DEFENDER_PER_ACCOUNT -and (Test-IsNoSQL) } -Tag @{ release = 'GA'; ruleSet = '2023_06'; 'Azure.WAF/pillar' = 'Security'; } -Labels @{ 'Azure.MCSB.v1/control' = 'DP-2', 'LT-1' } {
$defender = @(GetSubResources -ResourceType 'Microsoft.Security/advancedThreatProtectionSettings' |
Where-Object { $_.properties.isEnabled -eq $True })
Where-Object { $_.properties.isEnabled -eq $True })
$Assert.GreaterOrEqual($defender, '.', 1).Reason($LocalizedData.SubResourceNotFound, 'Microsoft.Security/advancedThreatProtectionSettings')
} -Configure @{ AZURE_COSMOS_DEFENDER_PER_ACCOUNT = $False }

# Synopsis: Cosmos DB has local authentication disabled.
Rule 'Azure.Cosmos.DisableLocalAuth' -Ref 'AZR-000420' -Type 'Microsoft.DocumentDb/databaseAccounts' -If { Test-IsNoSQL } -Tag @{ release = 'GA'; ruleSet = '2024_06'; 'Azure.WAF/pillar' = 'Security'; } -Labels @{ 'Azure.MCSB.v1/control' = 'IM-1' } {
$Assert.HasFieldValue($TargetObject, 'properties.DisableLocalAuth', $true)
}
#endregion Rules

#region Helper functions

function global:IsNoSQL {
function global:Test-IsNoSQL {
[CmdletBinding()]
param ()
process {
if (!$TargetObject.kind -or !$TargetObject.properties.capabilites.name) {
$True
}
param ( )

if ($TargetObject.kind -ne 'GlobalDocumentDB') {
return $false
}
if (-not $TargetObject.properties.capabilities) {
return $true
}
$TargetObject.properties.capabilities.Where({ $_.name -in @('EnableTable', 'EnableCassandra', 'EnableGremlin') }, 'First').Count -eq 0
}

#endregion Helper functions
21 changes: 16 additions & 5 deletions tests/PSRule.Rules.Azure.Tests/Azure.Cosmos.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,20 @@ Describe 'Azure.Cosmos' -Tag 'Cosmos', 'CosmosDB' {
$ruleResult.TargetName | Should -BeIn 'graph-B', 'nosql-A', 'nosql-B', 'nosql-C';
}

It 'Azure.Cosmos.DisableLocalAuth' {
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.Cosmos.DisableLocalAuth' };

# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult.Length | Should -Be 2;
$ruleResult.TargetName | Should -BeIn 'nosql-A', 'nosql-B';

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -BeIn 'nosql-C';
}

It 'Azure.Cosmos.PublicAccess' {
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.Cosmos.PublicAccess' };

Expand Down Expand Up @@ -186,11 +200,8 @@ Describe 'Azure.Cosmos' -Tag 'Cosmos', 'CosmosDB' {

# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult.Length | Should -Be 4;
$ruleResult.TargetName | Should -BeIn 'graph-A', 'graph-B', 'nosql-A', 'nosql-B';

$ruleResult[0].Reason | Should -BeExactly "A sub-resource of type 'Microsoft.Security/advancedThreatProtectionSettings' has not been specified.";
$ruleResult[1].Reason | Should -BeExactly "A sub-resource of type 'Microsoft.Security/advancedThreatProtectionSettings' has not been specified.";
$ruleResult.Length | Should -Be 2;
$ruleResult.TargetName | Should -BeIn 'nosql-A', 'nosql-B';

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
Expand Down
8 changes: 8 additions & 0 deletions tests/PSRule.Rules.Azure.Tests/Resources.Cosmos.json
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@
],
"databaseAccountOfferType": "Standard",
"enableAutomaticFailover": true,
"disableLocalAuth": false,
"publicNetworkAccess": "Enabled"
},
"ResourceGroupName": "test-rg",
Expand Down Expand Up @@ -342,7 +343,14 @@
],
"databaseAccountOfferType": "Standard",
"enableAutomaticFailover": true,
"disableLocalAuth": true,
"capabilities": [
{
"name": "EnableServerless"
}
],
"publicNetworkAccess": "Disabled"

},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.DocumentDB/databaseAccounts",
Expand Down
Loading