Security Model
Harrier reads EMR metadata, EMR Serverless metadata, EMR Containers metadata, S3 archived logs, CloudWatch Logs, CloudWatch metrics, selected repository files, selected read-only database diagnostics, and IAM role metadata.
Harrier must not directly change IAM policies, DB schemas, EMR clusters, data, or production configuration.
Write-capable tools must be separately allowlisted. PR preview is the default behavior.
harrier_prepare_pr can create a GitHub PR only when all write gates pass:
- request includes
dry_run=false - request includes
allow_pr_creation=true - server config has
HARRIER_ALLOW_PR_CREATION=true - target repo appears in
HARRIER_PR_REPO_ALLOWLIST - GitHub token is available through
HARRIER_GITHUB_TOKENorGITHUB_TOKEN
PR creation creates a branch and commits generated files under docs/harrier/. Patch hints are committed as a generated patch-plan document unless a future hint format supports a machine-applicable, allowlisted edit. Harrier does not merge PRs.
For DB scenarios, Harrier may run read-only diagnostics and suggest PR-ready SQL migrations or Spark JDBC code/config changes. It must not execute schema changes, write data, kill sessions, or apply migrations directly.
For Airflow or MWAA orchestration scenarios, Harrier may suggest PR-ready DAG changes such as sensors, pools, max_active_runs, timeouts, EMR step argument wiring, or context artifact updates. It must not trigger DAGs, mutate Airflow Variables or Connections, or change production schedules directly.
For runtime-specific recommendations, Harrier may suggest reviewed patch-plan changes for EMR Serverless job configuration, EMR Serverless/EKS monitoring configuration, EMR on EKS pod templates, or EMR on EKS container images. It must not update live applications, submit jobs, change Kubernetes resources, push images, or alter log retention directly.
For SQL plan scenarios, Harrier should prefer bounded read-only diagnostics such as EXPLAIN (FORMAT JSON) over EXPLAIN ANALYZE unless a query is known to be safe and bounded.
For long-running jobs, Harrier may inspect read-only Spark/YARN/EMR state, CloudWatch metrics, logs, Spark event evidence, repository code, and read-only DB diagnostics. It must not kill jobs, resize clusters, change Spark configuration, or apply database changes directly. Recommended changes should be PR-ready suggestions or explicit operator runbook steps.
For S3 log evidence, Harrier must read bounded byte ranges only, redact likely secrets before storing excerpts, and flag prompt-like text embedded in logs as untrusted evidence.
The Initial Diagnosis Report is generated from the same redacted structured evidence. human_report_markdown may include bounded log excerpts, but those excerpts remain evidence, not instructions. Agents and operators must not execute commands, URLs, SQL, shell fragments, IAM snippets, or Kubernetes fragments that appear inside a log excerpt unless they are separately reviewed as an intentional remediation plan.
Diagnosis statuses are triage signals only. PASS, ISSUE, WARN, UNKNOWN, and NOT_CHECKED should not authorize mutations. They only guide the next detailed investigation step.
Runtime AWS Permissions
Harrier should run with read-only permissions scoped to the account, region, and log buckets/groups needed for the requested runtime. The MCP caller supplies identifiers; Harrier should not enumerate unrelated fleets unless a future tool explicitly adds discovery.
EMR on EC2 investigations require read access to:
elasticmapreduce:DescribeCluster
elasticmapreduce:DescribeStep
elasticmapreduce:ListInstanceGroups
elasticmapreduce:ListSteps
s3:ListBucket
s3:GetObject
cloudwatch:GetMetricStatistics
EMR Serverless investigations require read access to:
emr-serverless:GetApplication
emr-serverless:GetJobRun
emr-serverless:ListJobRunAttempts
s3:ListBucket
s3:GetObject
logs:DescribeLogStreams
logs:GetLogEvents
cloudwatch:GetMetricStatistics
EMR on EKS investigations require read access to:
emr-containers:DescribeVirtualCluster
emr-containers:DescribeJobRun
emr-containers:ListJobRuns
s3:ListBucket
s3:GetObject
logs:DescribeLogStreams
logs:GetLogEvents
These permissions should be resource-scoped where AWS supports it. S3 access should be limited to configured EMR log buckets and prefixes. CloudWatch Logs access should be limited to known EMR Serverless and EMR on EKS log groups.
The Terraform ECS task role grants the read actions needed by all three supported runtimes. Tighten the broad resources for production accounts by replacing wildcard S3 and Logs resources with the known log buckets, prefixes, and log groups used by the workloads the Agent Space may investigate.
Example read-only policy shape for a single account and region:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EmrEc2Read",
"Effect": "Allow",
"Action": [
"elasticmapreduce:DescribeCluster",
"elasticmapreduce:DescribeStep",
"elasticmapreduce:ListInstanceGroups",
"elasticmapreduce:ListSteps"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": "ap-southeast-2"
}
}
},
{
"Sid": "EmrServerlessRead",
"Effect": "Allow",
"Action": [
"emr-serverless:GetApplication",
"emr-serverless:GetJobRun",
"emr-serverless:ListJobRunAttempts"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": "ap-southeast-2"
}
}
},
{
"Sid": "EmrContainersRead",
"Effect": "Allow",
"Action": [
"emr-containers:DescribeVirtualCluster",
"emr-containers:DescribeJobRun",
"emr-containers:ListJobRuns"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": "ap-southeast-2"
}
}
},
{
"Sid": "LogBucketList",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::example-emr-log-bucket",
"Condition": {
"StringLike": {
"s3:prefix": [
"emr/*",
"emr-serverless/*",
"emr-eks/*"
]
}
}
},
{
"Sid": "LogObjectRead",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": [
"arn:aws:s3:::example-emr-log-bucket/emr/*",
"arn:aws:s3:::example-emr-log-bucket/emr-serverless/*",
"arn:aws:s3:::example-emr-log-bucket/emr-eks/*"
]
},
{
"Sid": "CloudWatchLogsRead",
"Effect": "Allow",
"Action": [
"logs:DescribeLogStreams",
"logs:GetLogEvents"
],
"Resource": [
"arn:aws:logs:ap-southeast-2:111122223333:log-group:/aws/elasticmapreduce/*:*",
"arn:aws:logs:ap-southeast-2:111122223333:log-group:/harrier-demo/emr-serverless:*",
"arn:aws:logs:ap-southeast-2:111122223333:log-group:/harrier-demo/emr-eks:*"
]
},
{
"Sid": "CloudWatchMetricsRead",
"Effect": "Allow",
"Action": [
"cloudwatch:GetMetricData",
"cloudwatch:GetMetricStatistics",
"cloudwatch:ListMetrics"
],
"Resource": "*"
}
]
}
Some AWS APIs do not support resource-level scoping for every read action. In those cases, keep Resource: "*" but scope by account, region, deployment role, and Agent Space membership. Validate final policies with IAM Access Analyzer or the IAM policy simulator before enabling a broad production Agent Space.
Optional Kubernetes Access
Optional Kubernetes diagnostics are available for EMR on EKS pod state. Kubernetes access is not required for baseline EKS investigation and must be treated as best-effort read-only evidence.
If enabled, Kubernetes permissions should be limited to the target namespace and to read-only verbs for pod diagnostics:
get
list
watch
Suggested Kubernetes resources:
pods
pods/log
events
Harrier must not create, patch, delete, exec into, port-forward to, or restart Kubernetes resources. Pod status, restart counts, waiting reasons, OOMKilled markers, ImagePullBackOff, Evicted, and scheduling failures are evidence only.
Namespace-scoped RBAC example:
apiVersion: v1
kind: ServiceAccount
metadata:
name: harrier-pod-reader
namespace: emr-jobs
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: harrier-pod-reader
namespace: emr-jobs
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
- apiGroups: ["", "events.k8s.io"]
resources: ["events"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: harrier-pod-reader
namespace: emr-jobs
subjects:
- kind: ServiceAccount
name: harrier-pod-reader
namespace: emr-jobs
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: harrier-pod-reader
When Harrier runs outside the EKS cluster, map the MCP runtime's IAM principal to a Kubernetes user or group through the cluster's normal access mechanism, then bind that subject to the same read-only Role. The default ECS container image does not require Kubernetes access. It can still investigate EMR on EKS metadata and logs without pod diagnostics.
Kubernetes client behavior:
- If the optional Python
kubernetespackage is installed, Harrier tries in-cluster config first and then kubeconfig, usingtarget.eks_cluster_nameas the requested context when supplied. - If the Python package is unavailable or kubeconfig cannot load, Harrier falls back to
kubectlwhen it is available onPATH. It tries the supplied context first, then the current context. - If no Kubernetes client or readable config is available, Harrier returns a recoverable
NOT_CONFIGUREDwarning and continues. - If RBAC blocks pod reads, Harrier returns a recoverable
PERMISSION_DENIEDwarning and continues.