Appearance
Ops-Automation Identity Least Privilege Audit — LPRIV-010 through LPRIV-016
Audit of ops-automation pipeline identities, API keys, and service tokens. Completed April 2026 as part of the LPRIV least privilege workstream.
Identity Overview
| Story | Identity | Used By | Type |
|---|---|---|---|
| LPRIV-010 | kobe-security-audit | Maester M365 audit | Azure AD app registration |
| LPRIV-011 | kobe-security-audit | pim-audit.yml | Azure AD app registration (same) |
| LPRIV-012 | kobe-security-audit | HIPAA/compliance dashboards | Azure AD app registration (same) |
| LPRIV-013 | Cortex XDR API key | cortex-weekly-report.yml + cortex_agent.py | API key pair |
| LPRIV-014 | SES send identity | All email-reporting workflows | AWS IAM via github-deploy-main |
| LPRIV-015 | cirius-kobe-bot | Branch creation, PRs, commits | GitHub personal access token |
| LPRIV-016 | Telegram bot token | SecOps platform notifications | Telegram Bot API token |
LPRIV-010, LPRIV-011, LPRIV-012 — kobe-security-audit App Registration
App: kobe-security-audit (App ID: 8f9a3c24-8d9b-40b9-99e0-34a8c76759f6) SP Object ID: a373da7a-cb84-4520-b9a1-3040be9a1db6Type: Federated credential (GitHub Actions OIDC — Cirius-Group-Inc/ops-automation)
Date audited: April 15, 2026
This single app registration is used by multiple workflows in ops-automation. The same AZURE_CLIENT_ID GitHub secret is referenced by:
maester-m365-audit.yml(LPRIV-010)pim-audit.yml(LPRIV-011)weekly-hipaa-audit.yml,prod-security-dashboard.yml,intune-audit.yml,purview-audit.yml,dde-security-dashboard.yml(LPRIV-012)
Consented Graph Permissions (Application roles)
| Permission | Purpose | Status |
|---|---|---|
Policy.Read.ConditionalAccess | Maester: audit CA policies | ✅ Required |
RoleEligibilitySchedule.Read.Directory | pim-audit: read PIM eligibility schedules | ✅ Required |
DeviceManagementManagedDevices.Read.All | Intune audit: read managed devices | ✅ Required |
BitlockerKey.ReadBasic.All | HIPAA audit: verify BitLocker key escrow | ✅ Required |
UserAuthenticationMethod.Read.All | Maester: audit MFA registration | ✅ Required |
Mail.ReadWrite | Unused — removed 2026-04-15 (LPRIV-018) | ✅ REMOVED |
OnPremDirectorySynchronization.Read.All | Maester: Entra Connect sync health | ✅ Required |
SharePointTenantSettings.Read.All | Maester: SharePoint security settings | ✅ Required |
PrivilegedAccess.Read.AzureAD | pim-audit: read PIM role assignments | ✅ Required |
SecurityIdentitiesHealth.Read.All | Maester: identity security health | ✅ Required |
DirectoryRecommendations.Read.All | Maester: security recommendations | ✅ Required |
Directory.Read.All | Maester: read directory objects | ✅ Required |
ReportSettings.Read.All | Maester: reporting configuration | ✅ Required |
RoleManagement.Read.All | pim-audit: read role assignments | ✅ Required |
User.Read.All | pim-audit: read user objects | ✅ Required |
DeviceManagementRBAC.Read.All | Intune audit: read Intune RBAC | ✅ Required |
SecurityIdentitiesSensors.Read.All | Maester: security sensor health | ✅ Required |
DeviceManagementConfiguration.Read.All | Intune audit: read device config | ✅ Required |
Mail.Send | Unused — email delivery uses SES; removed 2026-04-15 (LPRIV-018) | ✅ REMOVED |
IdentityRiskEvent.Read.All | Maester: identity risk events | ✅ Required |
AuditLog.Read.All | Maester: audit log access | ✅ Required |
Policy.Read.All | Maester: all policy reads | ✅ Required |
Reports.Read.All | Dashboard: usage reports | ✅ Required |
ThreatHunting.Read.All | Maester: advanced threat hunting | ✅ Required |
Exchange Online Permission (Application role)
| Permission | Purpose | Status |
|---|---|---|
Exchange.ManageAsApp | Connect-ExchangeOnline in Maester | ⚠️ FLAGGED |
Exchange.ManageAsApp grants Exchange management-plane access for the service principal. Required by Maester to run Connect-ExchangeOnline for Exchange security tests. This is a Maester architectural requirement — Exchange Online does not support read-only app-only connectivity at the data plane level for PowerShell.
Mitigating control: The kobe-security-audit SP is registered in Exchange Online via New-ServicePrincipal but no management role assignments are granted — Maester runs read-only Exchange health checks only.
Windows Defender ATP Permissions (Application roles)
| Permission | Purpose | Status |
|---|---|---|
Machine.Read.All | Read machine/endpoint inventory from Defender | ✅ Required |
Vulnerability.Read.All | Read vulnerability findings from Defender | ✅ Required |
Flagged Findings
Remediated (2026-04-15): Mail.ReadWrite and Mail.Send removed (LPRIV-018).
Mail.ReadWrite was not used by any identified workflow. Email delivery in ops-automation uses AWS SES (via github-deploy-main role). Confirmed: no Python or PowerShell script in ops-automation calls the Graph mail send API. Both permissions were removed from the SP via Graph API DELETE appRoleAssignments. Count: 27 → 25.
Remaining flag: Exchange.ManageAsApp is very broad.
Full Exchange management access. Required for Maester Exchange tests. No narrower alternative for app-only Exchange Online connectivity. Mitigated by the absence of Exchange role group assignments for the SP.
Verdict: ✅ PASS (post-remediation) — 25 permissions remain (27 − 2 removed). Mail.ReadWrite and Mail.Send removed 2026-04-15. All remaining permissions are read-only except Exchange.ManageAsApp (required for Maester, tracked as broad).
LPRIV-013 — Cortex XDR API Key Scope
Key type: Advanced (HMAC-SHA256) or Standard — determined by CORTEX_API_KEY_TYPE secret Date audited: April 15, 2026
API Operations Used
| Endpoint | Operation | Purpose |
|---|---|---|
endpoints/get_endpoints | GET | Endpoint inventory and agent health |
incidents/get_incidents | GET | Active incident list |
vulnerabilities/get_vulnerabilities | GET | Vulnerability findings |
alerts/get_alerts | GET | Active alert list |
All operations are read-only data retrieval. No write, remediation, or response operations are performed via the API key.
Two consumers of this key:
ops-automation/cortex-weekly-report.yml— weekly scheduled report via GitHub Actionsbedrock-hub/agents/cortex_agent.py— 4-hour monitoring cycle
The agent reads the key from Key Vault cirius-openai-kv-prod secrets cortex-api-key and cortex-api-key-id at runtime.
Cortex XDR API Key Roles
Cortex XDR API keys have role-based access configured in the Cortex XDR console (Settings → Configurations → Integrations → API Keys). This audit cannot verify the assigned role without console access.
Finding (unverified): The key should have the minimum Cortex XDR API role that allows read-only access to endpoints, incidents, vulnerabilities, and alerts. This is typically the "Viewer" or read-only role in Cortex XDR.
Proposed action: Verify in Cortex XDR console that the API key is assigned the "Viewer" role (or equivalent minimum read role), not "Responder", "Analyst", or "Instance Admin". If a higher role is assigned, downgrade to Viewer.
Verdict: ⚠️ UNVERIFIED — operations are read-only but console access required to confirm the key's assigned role. Verify and report back.
LPRIV-014 — SES Sending Identity
Date audited: April 15, 2026
Email Delivery Architecture
All email sending in ops-automation workflows uses AWS SES, not Microsoft Graph:
- Sender identity: configured via
EMAIL_SENDERGitHub secret - Recipients:
SES_RECIPIENTSGitHub secret - AWS auth:
github-deploy-mainrole in management account (206820231356) via OIDC - Region: us-east-1
The AWS role github-deploy-main has AdministratorAccess (flagged in LPRIV-009), which includes SES send permissions. There is no separate scoped SES-only IAM role.
Finding: SES send operations run under the broad AdministratorAccess policy (Action: "*") on the management account deployment role. While this is an existing LPRIV-009 finding, SES-specific isolation is not currently possible given the CI/CD role architecture.
Separate note: The cirius-acs-smtp Azure AD app registration (App ID: 03cc0f1f-0cc4-4598-9df3-a403ccadcc49) is used for Azure Communication Services SMTP relay — a separate email path from the SES sending in ops-automation. ACS SMTP authenticates with Azure AD client credentials; no Graph permissions are assigned to this app (confirmed: zero app role assignments).
Verdict: ⚠️ FLAGGED — SES send runs under AdministratorAccess (LPRIV-009 tracking). ACS SMTP app is minimal (no permissions). No separate action for SES beyond LPRIV-009.
LPRIV-015 — Kobe GitHub Token Permissions
Account: cirius-kobe-bot (GitHub user — org member, not owner) Date audited: April 15, 2026
GitHub Org Role
| Attribute | Value |
|---|---|
| Org role | member (not owner) |
| State | Active |
Repository Access
Verified on azure-infra (representative):
| Permission | Granted | Notes |
|---|---|---|
pull (read) | ✅ | Read repository content, clone |
push (write) | ✅ | Create branches, push commits |
triage | ✅ | Label and manage issues/PRs (no merge) |
maintain | ❌ | No repository settings changes |
admin | ❌ | No admin access |
Finding: push access is required for the bot to create branches and push commits during automated PR workflows. triage allows labeling — appropriate for CI automation. admin and maintain are correctly absent.
Branch protection (1 required review) prevents the bot from merging its own PRs — the bot can push but cannot self-merge. This is the correct design.
Verdict: ✅ PASS — member role (not owner), write access scoped to repository operations, branch protection prevents self-merge, no admin access.
LPRIV-016 — Telegram Bot Token Scope
Date audited: April 15, 2026
Telegram Bot API Token Architecture
Telegram bot tokens do not have granular permission scopes — a token grants access to all Bot API methods the bot is eligible to use. Scope is controlled at the architectural level by which API methods the application calls.
Actual Usage (from codebase audit)
The Telegram bot is used exclusively for outbound notifications:
sendMessage— send alert notifications to the SecOps Telegram channeleditMessageText— update progress messages during long operationssendReaction— add emoji reactions to messages
The bot does NOT call:
- Any admin methods (channel administration, user banning)
- Message deletion (
deleteMessage) - File upload methods (
sendDocument,sendPhoto) except via explicit attachment flows - Webhook configuration endpoints
Key mitigating control: The bot token only functions in chats where the bot has been explicitly added. It cannot read messages from arbitrary Telegram chats.
CLAUDE.md architectural constraint: "Telegram is read-only — no buttons, no actions. All approvals in SecOps app only." This ensures no privileged operations are triggered via Telegram.
Verdict: ✅ PASS — No Telegram-side scope isolation mechanism exists (Bot API limitation), but architectural controls prevent misuse. Token access is limited to the SecOps notification channel. Bot does not perform admin or write operations.
Summary
| Story | Identity | Finding | Action |
|---|---|---|---|
| LPRIV-010 | kobe-security-audit (Maester) | Mail.ReadWrite + Mail.Send removed (LPRIV-018) | ✅ Done |
| LPRIV-011 | kobe-security-audit (pim-audit) | Shares identity with LPRIV-010 | ✅ Done |
| LPRIV-012 | kobe-security-audit (compliance) | Shares identity with LPRIV-010 | ✅ Done |
| LPRIV-013 | Cortex XDR API key | Role unverified — console access needed | Verify Viewer role in Cortex console |
| LPRIV-014 | SES via github-deploy-main | AdministratorAccess (tracked in LPRIV-009) | No separate action |
| LPRIV-015 | cirius-kobe-bot GitHub | member role, push-only, no self-merge | ✅ PASS |
| LPRIV-016 | Telegram bot token | No API scope isolation; architectural controls | ✅ PASS |
Priority Remediations
| Priority | Action | Story | Status |
|---|---|---|---|
| HIGH | Remove Mail.ReadWrite from kobe-security-audit | LPRIV-010/011/012 | ✅ Done 2026-04-15 |
| HIGH | Remove Mail.Send from kobe-security-audit | LPRIV-018 | ✅ Done 2026-04-15 |
| MEDIUM | Verify Cortex XDR API key assigned Viewer role | LPRIV-013 | Pending Rory console access |
Document History
| Date | Change | Author |
|---|---|---|
| April 2026 | Removed Mail.ReadWrite and Mail.Send from kobe-security-audit (LPRIV-018) | Kobe |
| April 2026 | Initial audit — LPRIV-010 through LPRIV-016 | Kobe |