Detect (DE) · Identity
Identity at the server side layer
external · Outside the agent entirely
If this concern is breached, how do we know?
What this cell does
K8s audit log captures every agent SA action; CloudTrail with Object Lock; SIEM rules on out-of-hours, unexpected source IP, identity reuse.
Artifacts (4)
audit-policy.yamlview on GitHub# ABOUTME: Kubernetes API server audit policy. Captures every agent SA action; identity-binding events at full request body.
# ABOUTME: Apply with --audit-policy-file= on kube-apiserver. Combined with --audit-log-path= or an audit webhook to a SIEM.
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
- RequestReceived
rules:
# 1. All agent SA mutations at RequestResponse level (full body).
- level: RequestResponse
users:
- "system:serviceaccount:agent-*"
verbs: ["create", "update", "patch", "delete", "deletecollection"]
# 2. Agent SA reads at Metadata level (which user, which resource, no body).
- level: Metadata
users:
- "system:serviceaccount:agent-*"
verbs: ["get", "list", "watch"]
# 3. Identity-binding events at full body, regardless of who initiated.
# These are the events that change who can do what; logging them at full
# detail lets the SIEM reconstruct privilege changes.
- level: RequestResponse
resources:
- group: "rbac.authorization.k8s.io"
resources: ["rolebindings", "clusterrolebindings", "roles", "clusterroles"]
- level: RequestResponse
resources:
- group: ""
resources: ["serviceaccounts"]
# 4. Secret reads/writes at full body. Secrets are credential material.
- level: RequestResponse
resources:
- group: ""
resources: ["secrets"]
verbs: ["get", "create", "update", "patch", "delete"]
# 5. Drop noisy health checks and well-known events that do not warrant
# durable audit storage. Tune for your cluster's actual chatter.
- level: None
users:
- "system:kube-proxy"
- "system:kube-scheduler"
- "system:kube-controller-manager"
resources:
- group: ""
resources: ["endpoints", "services", "nodes"]
verbs: ["get", "list", "watch"]
# 6. Default: log at Metadata level so we have at least the who-and-what
# for everything not covered above.
- level: Metadata
enable-cloudtrail.shview on GitHub#!/usr/bin/env bash
# ABOUTME: Provisions a multi-region CloudTrail trail delivering to an Object-Lock S3 bucket with log-file validation.
# ABOUTME: Pair with the immutable-backup bucket from controls/blast-radius/server-side/. Trail name is per-environment.
set -euo pipefail
TRAIL_NAME="${TRAIL_NAME:-agent-audit}"
BUCKET="${BUCKET:-agent-cloudtrail-immutable}"
REGION="${AWS_REGION:-us-east-1}"
if [[ -z "${AWS_PROFILE:-}" ]]; then
echo "Set AWS_PROFILE to a profile with cloudtrail:CreateTrail and s3:PutBucketPolicy." >&2
exit 1
fi
# Bucket policy that allows CloudTrail to write but no one to delete.
# Object Lock on the bucket prevents log tampering even with bucket-write.
cat > /tmp/cloudtrail-bucket-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AWSCloudTrailAclCheck",
"Effect": "Allow",
"Principal": { "Service": "cloudtrail.amazonaws.com" },
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::${BUCKET}"
},
{
"Sid": "AWSCloudTrailWrite",
"Effect": "Allow",
"Principal": { "Service": "cloudtrail.amazonaws.com" },
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::${BUCKET}/AWSLogs/*",
"Condition": {
"StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control" }
}
}
]
}
EOF
aws --profile "$AWS_PROFILE" s3api put-bucket-policy \
--bucket "$BUCKET" \
--policy file:///tmp/cloudtrail-bucket-policy.json
aws --profile "$AWS_PROFILE" cloudtrail create-trail \
--name "$TRAIL_NAME" \
--s3-bucket-name "$BUCKET" \
--include-global-service-events \
--is-multi-region-trail \
--enable-log-file-validation
aws --profile "$AWS_PROFILE" cloudtrail put-event-selectors \
--trail-name "$TRAIL_NAME" \
--event-selectors '[{
"ReadWriteType": "All",
"IncludeManagementEvents": true,
"DataResources": [
{"Type": "AWS::S3::Object", "Values": ["arn:aws:s3:::"]},
{"Type": "AWS::Lambda::Function", "Values": ["arn:aws:lambda"]}
]
}]'
aws --profile "$AWS_PROFILE" cloudtrail start-logging --name "$TRAIL_NAME"
echo "CloudTrail $TRAIL_NAME provisioned and logging."
echo ""
echo "Subscribe a SIEM to the trail via EventBridge:"
echo " aws events put-rule --name agent-cloudtrail-to-siem \\"
echo " --event-pattern '{\"source\":[\"aws.cloudtrail\"]}' "
sigma-out-of-hours.yamlview on GitHub# ABOUTME: Sigma detection rule for agent SA used outside the expected business-hours window.
# ABOUTME: Tune the hours range, weekend behavior, and on-call exception list for your team's working pattern.
title: Agent identity used outside expected hours
id: 6f6c8b3a-1e2d-4a3c-9d4e-3b7c8a9f0e1d
status: experimental
description: >
Detects use of an agent ServiceAccount or IAM principal outside the
expected business-hours window. Most agents in our environment operate
09:00-18:00 weekdays. Off-hours activity is an indicator of compromised
credentials, a forgotten cron job firing under an agent identity, or a
legitimate but undocumented operator action.
references:
- https://github.com/peopleforrester/agentic-covenants/blob/main/SENTINELS_MATRIX.md
author: agentic-covenants
date: 2026/05/08
logsource:
product: kubernetes
service: audit
detection:
selection:
user.username|startswith: 'system:serviceaccount:agent-'
filter_business_hours:
requestReceivedTimestamp|in_window:
hours_local: '09:00..18:00'
weekdays: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
filter_oncall_exceptions:
user.username|in:
- 'system:serviceaccount:agent-oncall-pager:rotate-on-call'
condition: selection and not filter_business_hours and not filter_oncall_exceptions
falsepositives:
- On-call rotation agents (add to filter_oncall_exceptions).
- Engineers running agents during incident response (treat as alert worth surfacing, not silencing).
- Cross-timezone teams (parameterize hours_local per agent or per region).
level: medium
tags:
- agent
- identity
- sentinels
sigma-unexpected-source-ip.yamlview on GitHub# ABOUTME: Sigma detection rule for agent identity used from a source IP outside the known agent-egress set.
# ABOUTME: known_agent_ips_lookup is a SIEM lookup table the operator maintains; the rule's correctness depends on it.
title: Agent identity used from unexpected source IP
id: 7e5f9c2b-2f3e-5b4d-ae5f-4c8d9b0e1f2a
status: experimental
description: >
Detects use of an agent ServiceAccount or IAM principal from a source IP
not in the known agent-egress set. Agent egress IPs are stable: NAT
gateway, EKS node CIDR, GitHub Actions IP ranges. A source IP outside this
set is an indicator of credential exfiltration to an external host or of
a misconfigured cluster path.
references:
- https://github.com/peopleforrester/agentic-covenants/blob/main/SENTINELS_MATRIX.md
author: agentic-covenants
date: 2026/05/08
logsource:
product: aws
service: cloudtrail
detection:
selection:
userIdentity.sessionContext.sessionIssuer.userName|startswith: 'claude-'
filter:
sourceIPAddress|in: '@known_agent_ips_lookup'
condition: selection and not filter
falsepositives:
- New NAT gateway provisioned and lookup table not updated (process; do not silence).
- GitHub Actions runner IP rotation (use the published IP range, not specific IPs).
level: high
tags:
- agent
- identity
- sentinels
Cell notes
Sentinels, Identity / Server-side
Control. Cloud audit log attributes every API call to a verified identity. Alert on identity not in expected set, identity used outside expected hours, identity used from unexpected source IP, identity reuse across agents.
Strength. Authoritative and external. Bypass requires audit logging not enabled, immutable storage not configured, or SIEM rule based on the wrong identifier (e.g. STS opaque session ID instead of resolved role ARN).
Tooling
- - Kubernetes API server with audit logging configured.
- - AWS CloudTrail with Object Lock on the destination S3 bucket. (GCP Audit Logs or Azure Monitor for the equivalent.)
- - A SIEM with Sigma-style detection rules.
Files in this directory
- -
audit-policy.yaml, Kubernetes audit policy that captures every agent SA action at RequestResponse level for mutations and Metadata level for reads. Identity-binding events (RoleBindings, ServiceAccount creation) are captured at full body. - -
enable-cloudtrail.sh, provisions a multi-region CloudTrail trail with log file validation enabled, delivering to an Object-Lock S3 bucket (provisioned in../../../controls/blast-radius/server-side/s3-immutable-backups.sh). - -
sigma-out-of-hours.yaml, Sigma rule firing when an agent SA is used outside the expected business-hours window. - -
sigma-unexpected-source-ip.yaml, Sigma rule firing when the source IP of an agent action is outside the known agent-egress IP set.
Verification
# 1. Audit log captures agent SA actions
kubectl --as=system:serviceaccount:agent-claude-prod:claude-code get pods
grep "claude-code" /var/log/kubernetes/audit.log | tail -1
# expected: user.username with the agent SA
# 2. CloudTrail captures IAM action attributable to agent
aws --profile claude-code-prod sts get-caller-identity
sleep 60 # CloudTrail has delivery delay
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=Username,AttributeValue=claude-code-prod \
| jq '.Events | length'
# expected: greater than 0
# 3. SIEM rule fires on out-of-hours
# Manually run an action at 03:00 local time; alert should fire within minutes.
Common mistakes
- - K8s audit policy not applied because the flag was not set on API server start. Verify with a known kubectl call against an audit log entry.
- - CloudTrail bucket without Object Lock; an attacker with bucket-write deletes evidence.
- - SIEM rule based on
userIdentity.principalIdinstead of resolved role ARN. STS sessions present opaque IDs. - - Audit log retention shorter than incident discovery window. 30 days is the floor; 365 days is defensible for compliance.
Citation
NIST CSF 2.0 DE.CM-01, DE.CM-09, DE.AE-02. NIST SP 800-92.
Primary failure modes
Documented, not hypothetical. A control whose bypass is undocumented is worse than no control, because somebody trusted it.
- K8s audit policy not applied
- CloudTrail bucket without Object Lock
- SIEM rule based on userIdentity.principalId instead of resolved role ARN
Crosswalk
| NIST CSF 2 0 | DE.CM-01, DE.CM-09, DE.AE-02 |
|---|---|
| OTHER | NIST SP 800-92 |
Cite this cell:
https://agenticcovenants.com/detect/identity/server-side/