Query Details

Sign-in with Azure AD Federated Credentials from new GitHub workflow

Fed Cred Auth From New Workflow

Query

let starttime = 14d;
let endtime = 4h;
let GitHubFederated = _GetWatchlist('GitHubFederatedCredentials');
// Generates list of workflow jobs in the past
let HistoricDefs = GitHubAuditLogPolling_CL
| where TimeGenerated between (ago(starttime) .. ago(endtime))
| join kind=inner (GitHubFederated) on $left.repo_s == $right.Repo
| where action_s == "workflows.prepared_workflow_job"
| summarize HistoricCount=count() by job_workflow_ref_s, repo_s, ServicePrincipalId, ServicePrincipalName;
// Lookup for prepared_workflow_job in specific time range to get job_workflow_ref
GitHubAuditLogPolling_CL
| where TimeGenerated >= ago(endtime)
// Lookup if WatchList includes repo as Federated Credentials
| join kind=inner (GitHubFederated) on $left.repo_s == $right.Repo
| where action_s == "workflows.prepared_workflow_job"
| summarize by job_workflow_ref_s, repo_s, workflow_run_id_d, ServicePrincipalId, ServicePrincipalName
// Check if workflow was used in the past
| join kind= leftouter (HistoricDefs) on job_workflow_ref_s
| where job_workflow_ref_s !in (HistoricDefs)
// Lookup for workflows.completed_workflow_run to get started and completed time range and conclusion of workflow
| join kind=innerunique (
    GitHubAuditLogPolling_CL
    | where action_s == "workflows.completed_workflow_run"
    | project workflow_run_id_d, name_s, actor_s, event_s, action_s, started_at_t, completed_at_t, conclusion_s
    ) on $left.workflow_run_id_d == $right.workflow_run_id_d
// Check if Workflow has used Federated Credentials, experimantal approach to use timestamp because of missing alternate reference
| extend Organization = tostring(split(repo_s, "/")[0])
| extend Repository = tostring(split(repo_s, "/")[1])
| project WorkflowRunId = workflow_run_id_d, WorkflowName = name_s,Actor = actor_s, WorkflowRef = job_workflow_ref_s, Repository, Organization, WorkflowStartedTime = started_at_t, WorkflowCompletedTime = completed_at_t, WorkflowConslusion = conclusion_s, ServicePrincipalId, ServicePrincipalName, HistoricCount
| extend ServicePrincipalId = tostring(ServicePrincipalId)
// Optional: Enrich all sign-in events in time window to the workflow run
| join kind=inner (
    AADServicePrincipalSignInLogs
        | project AADSignInTime = TimeGenerated, AADCorrelationId = CorrelationId, IPAddress, ServicePrincipalResource = ResourceDisplayName, Location, ServicePrincipalId, ServicePrincipalCredentialKeyId
        | where ServicePrincipalCredentialKeyId == "00000000-0000-0000-0000-000000000000"
        ) on $left.ServicePrincipalId == $right.ServicePrincipalId
| where AADSignInTime between (todatetime(WorkflowStartedTime) .. todatetime(WorkflowCompletedTime))
| project AADSignInTime, WorkflowRunId, WorkflowName, AccountCustomEntity = Actor, WorkflowRef, Repository, Organization, WorkflowStartedTime, WorkflowCompletedTime, WorkflowConslusion, AADCorrelationId, Location, IPCustomEntity = IPAddress, ServicePrincipalResource, ServicePrincipalName, ServicePrincipalId, HistoricCount

Explanation

This query is designed to detect new GitHub workflows that use Azure AD federated credentials for authentication. Here's a simple breakdown of what the query does:

  1. Objective: The query aims to identify new GitHub workflows that utilize federated credentials to authenticate with Azure AD. It focuses on workflows from specific repositories listed in a watchlist called "GitHubFederatedCredentials."

  2. Time Frame: It examines GitHub audit logs over the past 14 days, with a focus on activities within the last 4 hours.

  3. Historic Data: It first gathers a list of workflow jobs that have been executed in the past from the specified repositories.

  4. Current Data: It then looks for new workflow jobs in the last 4 hours from the same repositories.

  5. Comparison: The query checks if these new workflows have been seen before by comparing them against the historic data. If a workflow is new (i.e., not seen in the past 2 weeks), it proceeds to further analysis.

  6. Workflow Details: For the new workflows, it retrieves details such as the workflow's start and completion times, the actor who initiated it, and its conclusion status.

  7. Federated Credentials Check: It checks if these workflows have used federated credentials by correlating the workflow execution time with Azure AD sign-in events.

  8. Output: The final output includes details about the workflow run, the actor, the repository and organization, the workflow's execution times, and any associated Azure AD sign-in events.

  9. Severity and Tactics: The detection is marked with medium severity and is associated with tactics like Persistence and Impact, indicating potential security concerns.

  10. Entity Mappings: It maps certain fields to entities like Account and IP for further analysis or alerting.

Overall, this query helps in monitoring and detecting potentially unauthorized or suspicious use of federated credentials in GitHub workflows, which could indicate a security risk.

Details

Thomas Naunheim profile picture

Thomas Naunheim

Released: February 9, 2024

Tables

GitHubAuditLogPolling_CLAADServicePrincipalSignInLogs

Keywords

AzureADGitHubWorkflowFederatedCredentialsServicePrincipalIdServicePrincipalNameRepositoryOrganizationActorLocationIPAddressAccountCustomEntity

Operators

letbetweenagojoinonwheresummarizebyprojectextendsplittostringintodatetime

Severity

Medium

Tactics

PersistenceImpact

MITRE Techniques

Frequency: 14d

Period: 4h

Actions

GitHub