Microsoft Sentinel Analytic Rules
cloudbrothers.infoAzure Sentinel RepoToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

Azure DevOps Variable Secret Not Secured

Back
Id4ca74dc0-8352-4ac5-893c-73571cc78331
RulenameAzure DevOps Variable Secret Not Secured
DescriptionCredentials used in the build process may be stored as Azure DevOps variables. To secure these variables they should be stored in KeyVault or marked as Secrets.

This detection looks for new variables added with names that suggest they are credentials but where they are not set as Secrets or stored in KeyVault.
SeverityMedium
TacticsCredentialAccess
TechniquesT1552
KindScheduled
Query frequency1d
Query period1d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/AzureDevOpsAuditing/Analytic Rules/ADOSecretNotSecured.yaml
Version1.0.3
Arm template4ca74dc0-8352-4ac5-893c-73571cc78331.json
Deploy To Azure
let keywords = dynamic(["secret", "secrets", "password", "PAT", "passwd", "pswd", "pwd", "cred", "creds", "credentials", "credential", "key"]);
AzureDevOpsAuditing
| where OperationName =~ "Library.VariableGroupModified"
| extend Type = tostring(Data.Type)
| extend VariableGroupId = tostring(Data.VariableGroupId)
| extend VariableGroupName = tostring(Data.VariableGroupName)
| mv-expand Data.Variables
| where VariableGroupName has_any (keywords) or Data_Variables has_any (keywords)
| where Type != "AzureKeyVault"
| where Data_Variables !has "IsSecret"
| extend timestamp = TimeGenerated
| extend AccountName = tostring(split(ActorUPN, "@")[0]), AccountUPNSuffix = tostring(split(ActorUPN, "@")[1])
status: Available
queryFrequency: 1d
description: |
  'Credentials used in the build process may be stored as Azure DevOps variables. To secure these variables they should be stored in KeyVault or marked as Secrets. 
  This detection looks for new variables added with names that suggest they are credentials but where they are not set as Secrets or stored in KeyVault.'  
severity: Medium
version: 1.0.3
relevantTechniques:
- T1552
name: Azure DevOps Variable Secret Not Secured
triggerThreshold: 0
kind: Scheduled
query: |
  let keywords = dynamic(["secret", "secrets", "password", "PAT", "passwd", "pswd", "pwd", "cred", "creds", "credentials", "credential", "key"]);
  AzureDevOpsAuditing
  | where OperationName =~ "Library.VariableGroupModified"
  | extend Type = tostring(Data.Type)
  | extend VariableGroupId = tostring(Data.VariableGroupId)
  | extend VariableGroupName = tostring(Data.VariableGroupName)
  | mv-expand Data.Variables
  | where VariableGroupName has_any (keywords) or Data_Variables has_any (keywords)
  | where Type != "AzureKeyVault"
  | where Data_Variables !has "IsSecret"
  | extend timestamp = TimeGenerated
  | extend AccountName = tostring(split(ActorUPN, "@")[0]), AccountUPNSuffix = tostring(split(ActorUPN, "@")[1])  
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/AzureDevOpsAuditing/Analytic Rules/ADOSecretNotSecured.yaml
requiredDataConnectors: []
tactics:
- CredentialAccess
id: 4ca74dc0-8352-4ac5-893c-73571cc78331
queryPeriod: 1d
entityMappings:
- fieldMappings:
  - columnName: ActorUPN
    identifier: FullName
  - columnName: AccountName
    identifier: Name
  - columnName: AccountUPNSuffix
    identifier: UPNSuffix
  entityType: Account
- fieldMappings:
  - columnName: IpAddress
    identifier: Address
  entityType: IP
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/4ca74dc0-8352-4ac5-893c-73571cc78331')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/4ca74dc0-8352-4ac5-893c-73571cc78331')]",
      "properties": {
        "alertRuleTemplateName": "4ca74dc0-8352-4ac5-893c-73571cc78331",
        "customDetails": null,
        "description": "'Credentials used in the build process may be stored as Azure DevOps variables. To secure these variables they should be stored in KeyVault or marked as Secrets. \nThis detection looks for new variables added with names that suggest they are credentials but where they are not set as Secrets or stored in KeyVault.'\n",
        "displayName": "Azure DevOps Variable Secret Not Secured",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "ActorUPN",
                "identifier": "FullName"
              },
              {
                "columnName": "AccountName",
                "identifier": "Name"
              },
              {
                "columnName": "AccountUPNSuffix",
                "identifier": "UPNSuffix"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "IpAddress",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/AzureDevOpsAuditing/Analytic Rules/ADOSecretNotSecured.yaml",
        "query": "let keywords = dynamic([\"secret\", \"secrets\", \"password\", \"PAT\", \"passwd\", \"pswd\", \"pwd\", \"cred\", \"creds\", \"credentials\", \"credential\", \"key\"]);\nAzureDevOpsAuditing\n| where OperationName =~ \"Library.VariableGroupModified\"\n| extend Type = tostring(Data.Type)\n| extend VariableGroupId = tostring(Data.VariableGroupId)\n| extend VariableGroupName = tostring(Data.VariableGroupName)\n| mv-expand Data.Variables\n| where VariableGroupName has_any (keywords) or Data_Variables has_any (keywords)\n| where Type != \"AzureKeyVault\"\n| where Data_Variables !has \"IsSecret\"\n| extend timestamp = TimeGenerated\n| extend AccountName = tostring(split(ActorUPN, \"@\")[0]), AccountUPNSuffix = tostring(split(ActorUPN, \"@\")[1])\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "severity": "Medium",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CredentialAccess"
        ],
        "techniques": [
          "T1552"
        ],
        "templateVersion": "1.0.3",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}