AnalysisType: rule
Filename: snyk_svcacct_change.py
RuleID: "Snyk.ServiceAccount.Change"
DisplayName: "Snyk Service Account Change"
Enabled: true
LogTypes:
- Snyk.GroupAudit
- Snyk.OrgAudit
Tags:
- Snyk
Severity: High
Description: >
Detects when Snyk Service Accounts are changed
Runbook: |
These actions in the Snyk Audit logs indicate that a ServiceAccount
has been created/deleted/modified.
Service Accounts are system user accounts with an API token
associated to it in place of standard user credentials.
All events where the Service Account's role is ADMIN have CRITICAL severity
Deletion events are marked with HIGH severity
Creation events are marked with HIGH severity
Edit events are marked with MEDIUM Severity
Reference: https://docs.snyk.io/snyk-admin/service-accounts
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
- event
Tests:
- Name: Snyk Org Service Account ADMIN role ( CRIT )
ExpectedResult: true
Log:
{
"content":
{
"role": "ADMIN",
"rolePublicId": "d8999999-aaaa-4444-9fff-955555555555",
"serviceAccountPublicId": "9ddddddd-4444-4111-9eee-188888888888",
},
"created": "2023-04-05 22:22:57.488",
"event": "org.service_account.create",
"groupId": "8fffffff-1555-4444-b000-b55555555555",
"orgId": "21111111-a222-4eee-8ddd-a99999999999",
"userId": "05555555-3333-4ddd-8ccc-755555555555",
}
- Name: Snyk Group Service Account ADMIN role ( CRIT )
ExpectedResult: true
Log:
{
"content":
{
"role":
{
"created": "1999-01-22T16:02:53.848Z",
"description": "Admin",
"groupPermissions":
[
"group.read",
"group.edit",
"group.iac.settings.read",
"group.iac.settings.edit",
"group.report.read",
"group.org.add",
"group.org.remove",
"group.org.list",
"group.user.add",
"group.user.read",
"group.user.remove",
"group.user.delete",
"group.user.role.edit",
"group.user.provision",
"group.service_account.create",
"group.service_account.read",
"group.service_account.edit",
"group.service_account.delete",
"group.audit.read",
"group.settings.read",
"group.settings.edit",
"group.notification_settings.read",
"group.notification_settings.edit",
"group.policy.read",
"group.policy.create",
"group.policy.edit",
"group.policy.delete",
"group.tag.read",
"group.tag.create",
"group.tag.delete",
"group.flags.read",
"group.flags.edit",
"group.settings.request_access.read",
"group.settings.request_access.edit",
"group.sso.read",
"group.sso.edit",
"group.sso.remove",
"group.roles.read",
"group.roles.create",
"group.roles.edit",
"group.roles.remove",
],
"id": 1,
"modified": "1999-01-07T12:36:51.716Z",
"name": "Group Admin",
"orgPermissions":
[
"org.read",
"org.create",
"org.edit",
"org.delete",
"org.report.read",
"org.project.create",
"org.project.read",
"org.project.edit",
"org.project.delete",
"org.project.status",
"org.project.test",
"org.project.move",
"org.project.integration.edit",
"org.project.jira.issue.read",
"org.project.jira.issue.create",
"org.project.ignore.create",
"org.project.ignore.read",
"org.project.ignore.edit",
"org.project.ignore.delete",
"org.project.pr.create",
"org.project.pr.skip",
"org.project.attributes.edit",
"org.project.tag.edit",
"org.service_account.create",
"org.service_account.read",
"org.service_account.edit",
"org.service_account.delete",
"org.user.add",
"org.user.invite",
"org.user.manage",
"org.user.read",
"org.user.delete",
"org.user.leave",
"org.user.provision",
"org.integration.read",
"org.integration.edit",
"org.package.test",
"org.billing.read",
"org.billing.edit",
"org.entitlements.read",
"org.audit_log.read",
"org.flags.read",
"org.flags.edit",
"org.outbound_webhook.read",
"org.outbound_webhook.create",
"org.outbound_webhook.delete",
"org.app.read",
"org.app.install",
"org.app.create",
"org.app.delete",
"org.app.edit",
"org.cloud_environments.read",
"org.cloud_environments.create",
"org.cloud_environments.delete",
"org.cloud_environments.edit",
"org.cloud_scans.read",
"org.cloud_scans.create",
"org.cloud_resources.read",
"org.cloud_artifacts.read",
"org.cloud_artifacts.create",
"org.cloud_custom_rules.read",
"org.cloud_custom_rules.create",
"org.cloud_custom_rules.edit",
"org.cloud_custom_rules.delete",
],
"publicId": "89999999-feee-4333-8ccc-5aaaaaaaaaaa",
"role": "ADMIN",
"userPermissions": ["user.activate", "user.deactivate"],
},
"serviceAccountPublicId": "98888888-1ccc-4aaa-9fff-d66666666666",
},
"created": "2021-02-09 17:46:16.622",
"event": "group.service_account.create",
"groupId": "8fffffff-1555-4444-b000-b55555555555",
"userId": "05555555-3333-4ddd-8ccc-755555555555",
}
- Name: Snyk Group Service Account Create - Viewer Role ( HIGH )
ExpectedResult: true
Log:
{
"content":
{
"role":
{
"created": "1999-01-22T16:02:53.848Z",
"description": "Viewer",
"groupPermissions": ["group.tag.read"],
"id": 3,
"modified": "1999-02-01T12:36:51.728Z",
"name": "Group Viewer",
"orgPermissions": ["org.read"],
"publicId": "24444444-addd-4ddd-a444-0ddddddddddd",
"role": "VIEWER",
"userPermissions": [],
},
"serviceAccountPublicId": "06666666-9eee-4ccc-8999-4bbbbbbbbbbb",
},
"created": "2021-01-08 17:13:01.355",
"event": "group.service_account.create",
"groupId": "8fffffff-1555-4444-b000-b55555555555",
"userId": "05555555-3333-4ddd-8ccc-755555555555",
}
- Name: Snyk Service Account Edit ( MEDIUM )
ExpectedResult: true
Log:
{
"groupId": "8fffffff-1555-4444-b000-b55555555555",
"userId": "05555555-3333-4ddd-8ccc-755555555555",
"event": "group.service_account.edit",
"content":
{
"after": { "name": "test-SA-after" },
"before": { "name": "test-SA-before" },
"serviceAccountPublicId": "41111111-3fff-4eee-b111-6bbbbbbbbbbb",
},
"created": "2023-02-12T23:57:35.522Z",
}
- Name: Snyk Group SSO Membership sync
ExpectedResult: false
Log:
{
"content": {},
"created": "2023-03-15 13:13:13.133",
"event": "group.sso.membership.sync",
"groupId": "8fffffff-1555-4444-b000-b55555555555",
}
# ------ paired body: snyk_svcacct_change.py ------
from panther_snyk_helpers import snyk_alert_context
ACTIONS = [
"group.service_account.create",
"group.service_account.delete",
"group.service_account.edit",
"org.service_account.create",
"org.service_account.delete",
"org.service_account.edit",
"org.service_account.membership.upsert",
]
def rule(event):
action = event.get("event", "<NO_EVENT>")
return action in ACTIONS
def title(event):
group_or_org = "<GROUP_OR_ORG>"
crud_operation = "<NO_OPERATION>"
action = event.get("event", "<NO_EVENT>")
if "." in action:
group_or_org = action.split(".")[0].title()
crud_operation = action.split(".")[-1].title()
return (
f"Snyk: [{group_or_org}] Service Account "
f"[{crud_operation}] "
f"performed by [{event.deep_get('userId', default='<NO_USERID>')}]"
)
def alert_context(event):
a_c = snyk_alert_context(event)
role = event.deep_get("content", "role", "role", default=None)
if not role:
role = event.deep_get("content", "role", default=None)
if role:
a_c["role_permission"] = role
return a_c
def dedup(event):
return (
f"{event.deep_get('userId', default='<NO_USERID>')}"
f"{event.deep_get('orgId', default='<NO_ORGID>')}"
f"{event.deep_get('groupId', default='<NO_GROUPID>')}"
f"{event.deep_get('event', default='<NO_EVENT>')}"
)
def severity(event):
action = event.get("event", "<NO_EVENT>")
role = event.deep_get("content", "role", "role", default=None)
if not role:
role = event.deep_get("content", "role", default=None)
if all(
[role == "ADMIN", action.endswith((".service_account.create", ".service_account.delete"))]
):
return "CRITICAL"
if action.endswith((".service_account.create", ".service_account.delete")):
return "HIGH"
return "MEDIUM"