Query Details
id: 4918822d-6b9a-49cf-ac81-c9d418fdbcd9
name: 'Azure Activity with Federated Credentials outside of GitHub Workflow activity'
description: |
'Service Principal with Federated Credentials has been used for Azure Management but no GitHub workflow or sign-in event was audited in the activity time window.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 4h
queryPeriod: 4h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- Impact
relevantTechniques:
- T1098
- T1496
query: |
// Workflow runs and sign-ins from GitHub
let GitHubFederated = _GetWatchlist('GitHubFederatedCredentials');
let GitHubEvents = GitHubFederated
| extend ServicePrincipalId = tostring(ServicePrincipalId)
| extend GitHubOrganization = tostring(split(Repo, "/")[0])
| extend GitHubRepository = tostring(split(Repo, "/")[1])
| extend FedCredSubjectIdentifier = SubjectIdentifier
| join kind=inner (
AADServicePrincipalSignInLogs
| where ServicePrincipalCredentialKeyId == "00000000-0000-0000-0000-000000000000"
)on $left.ServicePrincipalId == $right.ServicePrincipalId
| project AADSignInTime = TimeGenerated, AADCorrelationId = CorrelationId, IPAddress, ServicePrincipalResource = ResourceDisplayName, AADSignInLocation = Location, ServicePrincipalId, ServicePrincipalCredentialKeyId, AADSignInResult = ResultType, AADTokenId = UniqueTokenIdentifier, FedCredSubjectIdentifier = SubjectIdentifier, GitHubRepoName = Repo
| extend GitHubOrganization = tostring(split(GitHubRepoName, "/")[0])
| extend GitHubRepository = tostring(split(GitHubRepoName, "/")[1])
| join kind=inner (
GitHubAuditLogPolling_CL
| where action_s == "workflows.completed_workflow_run"
| project GitHubRepoName = repo_s, WorkflowRunId = workflow_run_id_d, WorkflowName = name_s, WorkflowActor = actor_s, WorkflowStartedTime = started_at_t, WorkflowCompletedTime = completed_at_t, WorkflowConslusion = conclusion_s
) on $left.GitHubRepoName == $right.GitHubRepoName
| where AADSignInTime between (todatetime(WorkflowStartedTime) .. todatetime(WorkflowCompletedTime));
// Azure Activities from Federated Credentials
GitHubFederated
| extend ServicePrincipalId = tostring(ServicePrincipalId)
| join kind=inner (
AzureActivity
| extend AzClaims = parse_json(Claims_d)
| extend AzObjProp = parse_json(Properties_d)
| extend AzResourceId = tostring(AzObjProp.entity)
| extend AzActivityResource = tostring(AzClaims.aud)
| project AzCorrelationId = CorrelationId, AzTimeStamp = TimeGenerated, AzIpAddress = CallerIpAddress, AzSpId = Caller, AzClaims = parse_json(Claims_d), AzObjProp = parse_json(Properties_d), AzResourceId = tostring(AzObjProp.entity), AzActivityResource = tostring(AzClaims.aud)
)on $left.ServicePrincipalId == $right.AzSpId
| join kind=leftouter GitHubEvents on $left.AzSpId == $right.ServicePrincipalId, $left.AzIpAddress == $right.IPAddress
| where isempty(WorkflowStartedTime) or AzTimeStamp !between (WorkflowStartedTime .. WorkflowCompletedTime)
| project AzResourceId, AzSpId, ServicePrincipalId, ServicePrincipalName, AzIpAddress, IPAddress, WorkflowStartedTime, WorkflowCompletedTime, AzTimeStamp
| extend timestamp = AzTimeStamp, AccountCustomEntity = ServicePrincipalName, IPCustomEntity = AzIpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
- entityType: AzureResource
fieldMappings:
- identifier: ResourceId
columnName: AzResourceId
version: 1.1.0
This query is looking for instances where a Service Principal with Federated Credentials has been used for Azure Management, but no GitHub workflow or sign-in event was audited during the specified time window. It checks for workflow runs and sign-ins from GitHub, as well as Azure activities from Federated Credentials. The query frequency is every 4 hours, and the severity is medium. The relevant techniques are T1098 and T1496, related to persistence and impact. The query does not require any specific data connectors.

Thomas Naunheim
Released: January 29, 2023
Tables
Keywords
Operators