Dredge - 1.0.0
⚡ Log collection, analysis, and rapid response in the cloud... pa' la hinchada⚡
TL;DR
- Python library + CLI for cloud incident response and threat hunting.
- AWS: containment, forensics, and hunting across IAM, EC2, RDS, ECS, S3, Lambda, KMS, GuardDuty, Security Hub, CloudTrail, and more.
- Kubernetes: containment, forensics, and hunting across RBAC, pods, nodes, NetworkPolicy, and Secrets — works against any cluster (EKS, GKE, AKS, or self-managed) via standard kubeconfig or service-account auth.
- GitHub: org/enterprise audit log hunting and containment (block/remove members, revoke deploy keys, delete webhooks, archive/lock down repos).
- GCP: Cloud Logging hunting (in progress).
- 1,100+ tests, ~98% coverage, 80% floor enforced in CI.
Dredge is designed for rapid cloud IR — especially when you don't have all the plumbing ready at 3AM. It exposes a clean, composable Python API you can import into your own tooling and a CLI for direct use from the terminal.
Current Features
Response (AWS) — Containment
| Action | Method |
|---|---|
| Disable / delete IAM access key | response.disable_access_key / delete_access_key |
| Disable / delete IAM user | response.disable_user / delete_user |
| Disable IAM role (detach policies, clear trust) | response.disable_role |
| Delete MFA devices for a user | response.delete_mfa_devices |
| Revoke active IAM sessions (deny policy) | response.revoke_active_sessions |
| Detach a single managed policy from user/role | response.detach_iam_policy |
| Block S3 public access (account-level) | response.block_s3_public_access |
| Block S3 public access (bucket-level) | response.block_s3_bucket_public_access |
| Block S3 object public access | response.block_s3_object_public_access |
| Quarantine S3 bucket (block public + deny-all external) | response.quarantine_s3_bucket |
| Network-isolate EC2 instances (forensic SG) | response.isolate_ec2_instances |
| Stop EC2 instances | response.stop_ec2_instances |
| Terminate EC2 instances (optional EBS snapshot) | response.terminate_ec2_instances |
| Block CIDRs via NACL deny rules | response.block_nacl_cidrs |
| Revoke specific security group rules | response.deauthorize_security_group_rules |
| Isolate RDS instance (empty SG, disable public access) | response.isolate_rds_instance |
| Scale ECS service to 0 | response.stop_ecs_service |
| Force-stop ECS task | response.stop_ecs_task |
| Schedule Secrets Manager secret for deletion | response.disable_secrets_manager_secret |
| Disable EventBridge rule | response.disable_eventbridge_rule |
| Terminate active SSM sessions on an instance | response.terminate_ssm_sessions |
| Throttle Lambda function to zero concurrency | response.disable_lambda_function |
| Disable KMS key | response.disable_kms_key |
| Schedule KMS key deletion | response.schedule_kms_key_deletion |
| Tag AWS resources by ARN | response.tag_resources |
Forensics (AWS)
| Action | Method |
|---|---|
| Snapshot EBS volume | forensics.get_ebs_snapshot |
| Snapshot all volumes on an EC2 instance | forensics.snapshot_instance_volumes |
| Capture Lambda environment variables | forensics.get_lambda_environment |
| Enable VPC flow logs (CloudWatch or S3) | forensics.enable_vpc_flow_logs |
| Retrieve completed SSM session history | forensics.capture_ssm_session_history |
| Check CloudTrail trail status and event selectors | forensics.get_cloudtrail_status |
Hunt / Detection (AWS)
| Action | Method |
|---|---|
| CloudTrail LookupEvents (user, key, event, IP) | hunt.lookup_events |
| GuardDuty findings (severity, type, time filters) | hunt.list_guardduty_findings |
| Security Hub findings (severity, workflow, product) | hunt.hunt_security_hub_findings |
| IAM Access Analyzer findings | hunt.hunt_access_analyzer_findings |
| AWS Config resource configuration history | hunt.hunt_config_resource_history |
| CloudWatch Logs Insights query | hunt.hunt_cloudwatch_logs |
| IAM credential report (all users, keys, MFA, last used) | hunt.get_iam_credential_report |
Hunt (GitHub)
- Org or Enterprise audit log search by
actor,action,repo,source_ip, time range. - Handles pagination and rate limiting.
Response (Kubernetes) — Containment
| Action | Method |
|---|---|
| Delete a RoleBinding / ClusterRoleBinding | response.revoke_role_binding / revoke_cluster_role_binding |
| Disable a ServiceAccount (delete tokens + bindings) | response.disable_service_account |
| Fully delete a ServiceAccount | response.delete_service_account |
| Force-delete a pod | response.delete_pod |
| Scale a Deployment (e.g. to 0) | response.scale_deployment |
| Cordon a node | response.cordon_node |
| Cordon + evict all pods on a node | response.drain_node |
| Remove a Node object from the cluster | response.delete_node |
| Isolate a pod with a deny-all NetworkPolicy | response.quarantine_pod |
| Isolate an entire namespace with a deny-all NetworkPolicy | response.quarantine_namespace |
| Delete a Secret | response.delete_secret |
| Apply labels to a pod/node/namespace/deployment | response.label_resource |
Forensics (Kubernetes)
| Action | Method |
|---|---|
| Capture a pod's full manifest | forensics.get_pod_manifest |
| Capture container logs | forensics.get_pod_logs |
| Capture Events for a pod | forensics.get_pod_events |
| Capture a node's full manifest | forensics.describe_node |
| Capture a workload controller's manifest (Deployment/StatefulSet/DaemonSet) | forensics.capture_workload_manifest |
| List pods scheduled to a node | forensics.list_pods_on_node |
| Run a diagnostic command in a pod (best-effort) | forensics.exec_pod_command |
Hunt (Kubernetes)
| Action | Method |
|---|---|
| Search Kubernetes Events (namespace, involved object, reason, time range) | hunt.list_events |
| Find RoleBindings/ClusterRoleBindings referencing a subject | hunt.list_role_bindings_for_subject |
| List pods running under a ServiceAccount | hunt.list_pods_by_service_account |
| Flag pods with elevated host access (privileged, hostNetwork/PID/IPC) | hunt.list_privileged_pods |
v1 hunting uses the built-in Kubernetes Events API only — flavor-agnostic, no audit-log plumbing required. Cloud-specific audit log retrieval (EKS → CloudWatch, GKE → Cloud Logging) is on the roadmap, composing with the existing aws_ir/gcp_ir hunt modules.
Installation
pip install dredge-ir
The distribution is named dredge-ir (the bare dredge name is taken on
PyPI by an unrelated package), but the import package and CLI are just
dredge — import dredge and dredge ... work as shown throughout this
README.
Dependencies are declared entirely in pyproject.toml — there is no separate
requirements.txt.
From source (for development — adds the test toolchain, then run the suite):
git clone https://github.com/dbnz-io/dredge.git
cd dredge
pip install -e ".[test]"
pytest -q
CLI structure
Commands are nested by provider → bucket → command:
dredge <provider> <bucket> <command> [options]
│ │ │
│ │ └─ e.g. cloudtrail, quarantine-pod, audit
│ └────────── hunt · response · forensics
└───────────────────── aws · k8s · github
Help is available at every level, revealing what's below it:
dredge --help # global overview, grouped by provider × bucket
dredge aws --help # the buckets under aws (hunt/response/forensics)
dredge aws hunt --help # the commands under aws hunt
dredge aws hunt cloudtrail --help # that command's full options
Global flags (auth, region, --dry-run) go before the provider, e.g.
dredge --aws-profile ir --region us-east-1 aws response disable-user --user bob.
Docker
docker build -t dredge:latest .
# or
podman build -t dredge:latest .
AWS Integration
Authentication
| Method | How |
|---|---|
| Default credential chain | env vars, ~/.aws/credentials, EC2/ECS role |
| Named profile | --aws-profile |
| Explicit keys | --aws-access-key-id + --aws-secret-access-key |
| Role assumption | --aws-role-arn (+ optional --aws-external-id) |
Region: --aws-region, or AWS_REGION / AWS_DEFAULT_REGION, or your profile config.
Global AWS CLI Flags
--aws-region AWS region (e.g. us-east-1)
--aws-profile Named AWS profile
--aws-access-key-id Explicit access key ID
--aws-secret-access-key
--aws-session-token STS session token
--aws-role-arn Role to assume
--aws-external-id External ID for role assumption
--dry-run Simulate without making changes
CLI Examples
IAM Containment
# Disable an access key
dredge --aws-profile dredge-role --region us-east-1 \
aws response disable-access-key --user compromised-user --access-key-id AKIA123456789
# Disable a user (deactivate keys, remove groups, delete login profile, detach policies)
dredge --aws-profile dredge-role --region us-east-1 \
aws response disable-user --user compromised-user
# Revoke active sessions (deny-all inline policy with TokenIssueTime condition)
dredge --aws-profile dredge-role --region us-east-1 \
aws response revoke-active-sessions --user compromised-user
# Detach a single policy from a role
dredge --aws-profile dredge-role --region us-east-1 \
aws response detach-iam-policy arn:aws:iam::123456789012:policy/AdminAccess --role-name OldRole
EC2 / Network Containment
# Network-isolate EC2 instances (forensic empty SG)
dredge --aws-profile dredge-role --region us-east-1 \
aws response isolate-ec2 i-0123456789abcdef0 i-0abcdef1234567890
# Block a CIDR at the NACL level
dredge --aws-profile dredge-role --region us-east-1 \
aws response block-nacl-cidrs --vpc-id vpc-abc123 --cidr 198.51.100.0/24
# Terminate an instance (snapshots EBS volumes first by default)
dredge --aws-profile dredge-role --region us-east-1 \
aws response terminate-ec2 i-0123456789abcdef0
RDS / ECS / Lambda
# Isolate an RDS instance
dredge --aws-profile dredge-role --region us-east-1 \
aws response isolate-rds my-prod-db
# Scale down a compromised ECS service
dredge --aws-profile dredge-role --region us-east-1 \
aws response stop-ecs-service my-cluster my-service
# Throttle a Lambda to zero
dredge --aws-profile dredge-role --region us-east-1 \
aws response disable-lambda --function-name my-function
# Terminate active SSM sessions on an instance
dredge --aws-profile dredge-role --region us-east-1 \
aws response terminate-ssm-sessions i-0123456789abcdef0
S3
# Block public access at account level
dredge --aws-profile dredge-role --region us-east-1 \
aws response block-s3-account --account-id 111122223333
# Quarantine a bucket (block public + deny all external principals)
dredge --aws-profile dredge-role --region us-east-1 \
aws response quarantine-s3-bucket suspicious-bucket
Threat Hunting
# Hunt CloudTrail events for a compromised access key
dredge --aws-profile dredge-role --region us-east-1 \
aws hunt cloudtrail --access-key-id AKIAIOSFODNN7EXAMPLE \
--start-time 2026-04-01T00:00:00Z --end-time 2026-04-12T00:00:00Z
# List high/critical GuardDuty findings
dredge --aws-profile dredge-role --region us-east-1 \
aws hunt guardduty --detector-id abc123 --severity-min 7.0
# Query Security Hub for critical findings
dredge --aws-profile dredge-role --region us-east-1 \
aws hunt security-hub --severity-label CRITICAL --severity-label HIGH
# Get IAM credential report (all users, key ages, MFA status)
dredge --aws-profile dredge-role --region us-east-1 \
aws response iam-credential-report
# Check AWS Config history for an EC2 instance
dredge --aws-profile dredge-role --region us-east-1 \
aws hunt config-history AWS::EC2::Instance i-0123456789abcdef0
Forensics
# Download the last 2 days of CloudTrail logs across every account/region
# from an org/Control Tower S3 bucket (date-aware: only lists dated folders
# inside the window, not years of history)
dredge --aws-profile dredge-role --region us-east-1 \
aws forensics download-s3-logs \
--bucket my-org-cloudtrail --prefix AWSLogs/ \
--destination ./ct-logs --days-ago 2
# Enable VPC flow logs
dredge --aws-profile dredge-role --region us-east-1 \
aws response enable-vpc-flow-logs vpc-abc123 \
--deliver-logs-permission-arn arn:aws:iam::123:role/FlowLogsRole
# Check CloudTrail is healthy and logging
dredge --aws-profile dredge-role --region us-east-1 \
aws response cloudtrail-status
GitHub Integration
Authentication
Token scopes required:
- Org audit logs:
admin:org,audit_log - Enterprise audit logs:
admin:enterprise,audit_log
Prefer the environment variable. Export GITHUB_TOKEN and let dredge read
it — passing --github-token <value> puts the secret in your shell history and
in the process list (ps), where other users on the host can see it. Use the
--github-token flag only for ad-hoc, throwaway tokens.
export GITHUB_TOKEN="ghp_..."
CLI Examples
These read the token from $GITHUB_TOKEN (no --github-token flag needed):
# Hunt today's activity for a user
dredge --github-org dbnz-io \
github hunt audit --actor sabastante --today --include all
# Hunt an action over a date range
dredge --github-enterprise dbnz-io \
github hunt audit --action repo.create \
--start-time 2025-01-01T00:00:00Z --end-time 2025-01-07T23:59:59Z
# Hunt suspicious IP activity
dredge --github-org dbnz-io \
github hunt audit --source-ip 203.0.113.50 --today --include all
Kubernetes Integration
Authentication
Dredge authenticates to Kubernetes the same way kubectl does, plus a first-class path for direct service-account/bearer-token auth (for library callers and automation that don't have a kubeconfig file on disk).
| Method | How |
|---|---|
| Kubeconfig ("auth like kubectl") | --k8s-kubeconfig (+ optional --k8s-context), or default ~/.kube/config / $KUBECONFIG. Cloud-specific token exchange (aws eks get-token, gke-gcloud-auth-plugin, kubelogin) is resolved entirely by the kubeconfig's exec plugin — dredge never needs to know which cloud is behind the cluster. |
| In-cluster | --k8s-in-cluster — uses the pod's mounted service-account token. |
| Explicit service-account / bearer token | --k8s-token (or --k8s-token-env-var, default K8S_TOKEN) + --k8s-api-server (+ optional --k8s-ca-cert). In the library, K8sAuthConfig.token_provider accepts a callable that is re-invoked before every API call (no dredge-side caching) — useful for short-lived, auto-rotating tokens. |
| Default | Tries in-cluster first, falls back to the default kubeconfig location. |
Region/cluster-flavor note: response and forensics methods run against the standard Kubernetes API and behave identically on EKS, GKE, AKS, or self-managed clusters — only auth differs by flavor, and kubeconfig already abstracts that.
Global Kubernetes CLI Flags
--k8s-kubeconfig Path to kubeconfig file
--k8s-context Kubeconfig context to use
--k8s-in-cluster Use the in-cluster (mounted) service account token
--k8s-token Explicit bearer/service-account token
--k8s-token-env-var Env var to read the token from (default: K8S_TOKEN)
--k8s-api-server API server URL (required with --k8s-token)
--k8s-ca-cert Path to CA cert file (used with --k8s-token)
--k8s-insecure-skip-tls-verify Disable TLS verification (used with --k8s-token)
--k8s-namespace Default namespace for namespaced subcommands
--dry-run Simulate without making changes
CLI Examples
# Quarantine a pod suspected of compromise
dredge --k8s-context prod-cluster --k8s-namespace default \
k8s response quarantine-pod suspicious-pod
# Cordon and drain a node
dredge --k8s-context prod-cluster \
k8s response drain-node ip-10-0-1-23.ec2.internal
# Disable a compromised ServiceAccount (delete tokens + bindings)
dredge --k8s-context prod-cluster --k8s-namespace default \
k8s response disable-service-account leaked-sa
# Hunt Events for a namespace over the last 24h (default window)
dredge --k8s-context prod-cluster \
k8s hunt events --namespace default --event-type Warning
# Find what a compromised ServiceAccount can do
dredge --k8s-context prod-cluster \
k8s hunt role-bindings-for-subject --kind ServiceAccount --name leaked-sa
# Flag pods running with elevated host access
dredge --k8s-context prod-cluster k8s hunt privileged-pods
# Capture forensic evidence before containment
dredge --k8s-context prod-cluster --k8s-namespace default \
k8s forensics get-pod-manifest suspicious-pod
Library Usage
AWS
from dredge import Dredge
from dredge.auth import AwsAuthConfig
auth = AwsAuthConfig(profile_name="dredge-role", region_name="us-east-1")
d = Dredge(auth=auth)
# Containment
d.aws_ir.response.disable_user("compromised-user")
d.aws_ir.response.isolate_ec2_instances(["i-0123456789abcdef0"])
d.aws_ir.response.quarantine_s3_bucket("sensitive-bucket")
# Hunting
result = d.aws_ir.hunt.lookup_events(access_key_id="AKIAIOSFODNN7EXAMPLE")
print(result.details["events"])
result = d.aws_ir.hunt.list_guardduty_findings("detector-id", severity_min=7.0)
print(result.details["findings"])
GitHub
from dredge import Dredge
from dredge.github_ir.config import GitHubIRConfig
cfg = GitHubIRConfig(org="dbnz-io", token="ghp_xxx")
d = Dredge(github_config=cfg)
res = d.github_ir.hunt.search_today(actor="sabastante")
print(res.details["events"])
Kubernetes
from dredge import Dredge
from dredge.k8s_ir.config import K8sAuthConfig
# "Auth like kubectl" -- resolves cloud-specific token exchange via the
# kubeconfig's exec plugin, same as `aws eks get-token` / `gke-gcloud-auth-plugin`.
cfg = K8sAuthConfig(context="prod-cluster")
d = Dredge(k8s_config=cfg)
# Containment
d.k8s_ir.response.quarantine_pod("default", "suspicious-pod")
d.k8s_ir.response.disable_service_account("default", "leaked-sa")
d.k8s_ir.response.drain_node("ip-10-0-1-23.ec2.internal")
# Hunting
result = d.k8s_ir.hunt.list_events(namespace="default", event_type="Warning")
print(result.details["events"])
result = d.k8s_ir.hunt.list_privileged_pods()
print(result.details["flagged_pods"])
Direct service-account auth (no kubeconfig needed -- e.g. for CI or a token pulled from a secrets manager):
cfg = K8sAuthConfig(
api_server="https://cluster.example.com",
token_provider=lambda: fetch_token_from_vault(), # re-invoked before every call
ca_cert_file="/path/to/ca.pem",
)
d = Dredge(k8s_config=cfg)
Roadmap
- Azure support (auth, IR actions, log hunting).
- Okta IR (suspend users, revoke sessions, hunt sign-in logs).
- GCP — expand beyond Cloud Logging hunting to full IR actions + coverage (currently in progress).
- Kubernetes: cloud-specific audit log hunting (EKS → CloudWatch, GKE → Cloud Logging) composed with
aws_ir/gcp_ir. - Kubernetes: pod filesystem/memory forensic capture via ephemeral debug containers.
- Kubernetes: cross-cloud credential revocation for IRSA (EKS) / Workload Identity (GKE/AKS) bound ServiceAccounts.
- IoC-based hunting (IP/domain/hash correlation across providers).
- Shodan + VirusTotal reintegration.
Contributing
PRs welcome. If you want to add modules (Azure, Okta, Datadog, JumpCloud), open an issue.
Release files for dredge-ir 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dredge_ir-1.0.0.tar.gz | 181.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dredge_ir-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 303.9 kB
Release files / dredge_ir-1.0.0.tar.gz
| Download URL | dredge_ir-1.0.0.tar.gz |
|---|---|
| Size | 181.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b26b06ef3ce794d315ed5c2f7d2bf214294fb1c587335cf2dc68f5335a7405e9
|
|
BLAKE2b-256 checksum How to use checksums |
5e572a21dd19f1476eef614f53846d09989850c874eeb5b800def2e1d46a7709
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency logRelease files / dredge_ir-1.0.0-py3-none-any.whl
| Download URL | dredge_ir-1.0.0-py3-none-any.whl |
|---|---|
| Size | 122.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fdb3456c27fef2d494e439a2eef3cbd65d287ccb62aaf8d16177ec38e9d8b8cd
|
|
BLAKE2b-256 checksum How to use checksums |
01f4d479438e1f3102ced920d746cea58fa984bf6d5d48a16dd5ffff3f62c334
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency log