mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-09-12 11:20:51 +03:00
Complete folder anatomy for all 649 cybersecurity skills + update LICENSE to Mahipal
- Add scripts/agent.py and references/api-reference.md to all remaining skills - Update all 648 LICENSE files: copyright now reads 'Mahipal' - Add implementing-security-monitoring-with-datadog (new skill with full anatomy) - All 649 skills now have: SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anthropic Agent Skills Contributors
|
||||
Copyright (c) 2025 Mahipal
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# API Reference: Implementing Kubernetes Network Policy with Calico
|
||||
|
||||
## Kubernetes NetworkPolicy
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny-all
|
||||
namespace: production
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes: [Ingress, Egress]
|
||||
```
|
||||
|
||||
## Calico GlobalNetworkPolicy
|
||||
|
||||
```yaml
|
||||
apiVersion: projectcalico.org/v3
|
||||
kind: GlobalNetworkPolicy
|
||||
metadata:
|
||||
name: deny-external
|
||||
spec:
|
||||
order: 100
|
||||
selector: app == "backend"
|
||||
types: [Ingress]
|
||||
ingress:
|
||||
- action: Deny
|
||||
source:
|
||||
nets: ["0.0.0.0/0"]
|
||||
```
|
||||
|
||||
## calicoctl CLI
|
||||
|
||||
```bash
|
||||
# Apply policy
|
||||
calicoctl apply -f policy.yaml
|
||||
# Get policies
|
||||
calicoctl get globalnetworkpolicy -o yaml
|
||||
# Get host endpoints
|
||||
calicoctl get hostendpoint
|
||||
```
|
||||
|
||||
## Policy Types
|
||||
|
||||
| Type | Scope | Ordering |
|
||||
|------|-------|----------|
|
||||
| NetworkPolicy | Namespace | Additive (OR) |
|
||||
| GlobalNetworkPolicy | Cluster-wide | Ordered by `order` field |
|
||||
|
||||
## Common Policy Patterns
|
||||
|
||||
| Pattern | Description |
|
||||
|---------|-------------|
|
||||
| Default deny | Empty podSelector, no rules |
|
||||
| Allow DNS | Egress to kube-system UDP/TCP 53 |
|
||||
| Allow ingress from namespace | namespaceSelector match |
|
||||
| Allow to external CIDR | ipBlock in egress |
|
||||
|
||||
### References
|
||||
|
||||
- Calico Docs: https://docs.tigera.io/calico/
|
||||
- K8s NetworkPolicy: https://kubernetes.io/docs/concepts/services-networking/network-policies/
|
||||
- Calico Policy Tutorial: https://docs.tigera.io/calico/latest/network-policy/
|
||||
@@ -0,0 +1,212 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Agent for auditing and generating Calico Kubernetes network policies."""
|
||||
|
||||
import json
|
||||
import argparse
|
||||
import subprocess
|
||||
import yaml
|
||||
from datetime import datetime
|
||||
from collections import Counter
|
||||
|
||||
|
||||
def kubectl_get(resource, namespace=None, label_selector=None):
|
||||
"""Get Kubernetes resources via kubectl."""
|
||||
cmd = ["kubectl", "get", resource, "-o", "json"]
|
||||
if namespace:
|
||||
cmd.extend(["-n", namespace])
|
||||
else:
|
||||
cmd.append("--all-namespaces")
|
||||
if label_selector:
|
||||
cmd.extend(["-l", label_selector])
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
||||
if result.returncode != 0:
|
||||
return {"error": result.stderr.strip()}
|
||||
return json.loads(result.stdout) if result.stdout.strip() else {}
|
||||
|
||||
|
||||
def list_network_policies():
|
||||
"""List all NetworkPolicy and Calico GlobalNetworkPolicy resources."""
|
||||
k8s_np = kubectl_get("networkpolicy")
|
||||
calico_gnp = kubectl_get("globalnetworkpolicy")
|
||||
return {
|
||||
"k8s_network_policies": k8s_np.get("items", []) if isinstance(k8s_np, dict) else [],
|
||||
"calico_global_policies": calico_gnp.get("items", []) if isinstance(calico_gnp, dict) else [],
|
||||
}
|
||||
|
||||
|
||||
def audit_network_policies(policies_path):
|
||||
"""Audit network policies for security gaps."""
|
||||
with open(policies_path) as f:
|
||||
data = json.load(f)
|
||||
policies = data if isinstance(data, list) else data.get("items", data.get("policies", []))
|
||||
findings = []
|
||||
namespaces_covered = set()
|
||||
|
||||
for policy in policies:
|
||||
metadata = policy.get("metadata", {})
|
||||
spec = policy.get("spec", {})
|
||||
ns = metadata.get("namespace", "default")
|
||||
namespaces_covered.add(ns)
|
||||
|
||||
policy_types = spec.get("policyTypes", [])
|
||||
if "Ingress" not in policy_types and "Egress" not in policy_types:
|
||||
findings.append({
|
||||
"policy": metadata.get("name", ""),
|
||||
"namespace": ns,
|
||||
"issue": "No policyTypes defined (defaults to ingress-only)",
|
||||
"severity": "MEDIUM",
|
||||
})
|
||||
|
||||
if "Egress" not in policy_types:
|
||||
findings.append({
|
||||
"policy": metadata.get("name", ""),
|
||||
"namespace": ns,
|
||||
"issue": "No egress policy - all outbound traffic allowed",
|
||||
"severity": "HIGH",
|
||||
})
|
||||
|
||||
ingress_rules = spec.get("ingress", [])
|
||||
for rule in ingress_rules:
|
||||
if not rule.get("from"):
|
||||
findings.append({
|
||||
"policy": metadata.get("name", ""),
|
||||
"issue": "Ingress rule allows from all sources",
|
||||
"severity": "HIGH",
|
||||
})
|
||||
|
||||
egress_rules = spec.get("egress", [])
|
||||
for rule in egress_rules:
|
||||
if not rule.get("to"):
|
||||
findings.append({
|
||||
"policy": metadata.get("name", ""),
|
||||
"issue": "Egress rule allows to all destinations",
|
||||
"severity": "MEDIUM",
|
||||
})
|
||||
|
||||
return {"findings": findings, "namespaces_covered": list(namespaces_covered),
|
||||
"total_policies": len(policies)}
|
||||
|
||||
|
||||
def generate_default_deny(namespace):
|
||||
"""Generate a default deny-all NetworkPolicy for a namespace."""
|
||||
return {
|
||||
"apiVersion": "networking.k8s.io/v1",
|
||||
"kind": "NetworkPolicy",
|
||||
"metadata": {"name": "default-deny-all", "namespace": namespace},
|
||||
"spec": {
|
||||
"podSelector": {},
|
||||
"policyTypes": ["Ingress", "Egress"],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def generate_allow_dns_egress(namespace):
|
||||
"""Generate a policy allowing DNS egress to kube-dns."""
|
||||
return {
|
||||
"apiVersion": "networking.k8s.io/v1",
|
||||
"kind": "NetworkPolicy",
|
||||
"metadata": {"name": "allow-dns-egress", "namespace": namespace},
|
||||
"spec": {
|
||||
"podSelector": {},
|
||||
"policyTypes": ["Egress"],
|
||||
"egress": [{
|
||||
"to": [{"namespaceSelector": {"matchLabels": {
|
||||
"kubernetes.io/metadata.name": "kube-system"}}}],
|
||||
"ports": [{"protocol": "UDP", "port": 53},
|
||||
{"protocol": "TCP", "port": 53}],
|
||||
}],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def generate_app_policy(namespace, app_label, allowed_ingress_labels=None,
|
||||
allowed_egress_ports=None):
|
||||
"""Generate a Calico-style network policy for an application."""
|
||||
policy = {
|
||||
"apiVersion": "networking.k8s.io/v1",
|
||||
"kind": "NetworkPolicy",
|
||||
"metadata": {"name": f"allow-{app_label}", "namespace": namespace},
|
||||
"spec": {
|
||||
"podSelector": {"matchLabels": {"app": app_label}},
|
||||
"policyTypes": ["Ingress", "Egress"],
|
||||
"ingress": [],
|
||||
"egress": [],
|
||||
},
|
||||
}
|
||||
if allowed_ingress_labels:
|
||||
for label in allowed_ingress_labels:
|
||||
policy["spec"]["ingress"].append({
|
||||
"from": [{"podSelector": {"matchLabels": {"app": label}}}],
|
||||
})
|
||||
if allowed_egress_ports:
|
||||
for port_info in allowed_egress_ports:
|
||||
policy["spec"]["egress"].append({
|
||||
"ports": [{"protocol": port_info.get("protocol", "TCP"),
|
||||
"port": port_info["port"]}],
|
||||
})
|
||||
return policy
|
||||
|
||||
|
||||
def check_unprotected_namespaces():
|
||||
"""Find namespaces without any network policies."""
|
||||
namespaces = kubectl_get("namespaces")
|
||||
policies = kubectl_get("networkpolicy")
|
||||
if isinstance(namespaces, dict) and "error" not in namespaces:
|
||||
all_ns = {item["metadata"]["name"] for item in namespaces.get("items", [])}
|
||||
else:
|
||||
return {"error": "Cannot list namespaces"}
|
||||
|
||||
protected_ns = set()
|
||||
if isinstance(policies, dict) and "error" not in policies:
|
||||
for item in policies.get("items", []):
|
||||
protected_ns.add(item.get("metadata", {}).get("namespace", "default"))
|
||||
|
||||
system_ns = {"kube-system", "kube-public", "kube-node-lease"}
|
||||
unprotected = all_ns - protected_ns - system_ns
|
||||
return {
|
||||
"total_namespaces": len(all_ns),
|
||||
"protected": len(protected_ns),
|
||||
"unprotected": list(unprotected),
|
||||
"severity": "HIGH" if unprotected else "INFO",
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Calico Network Policy Agent")
|
||||
parser.add_argument("--audit", help="Network policies JSON to audit")
|
||||
parser.add_argument("--namespace", help="Namespace for policy generation")
|
||||
parser.add_argument("--app", help="App label for policy generation")
|
||||
parser.add_argument("--action", choices=["audit", "generate", "check", "full"],
|
||||
default="full")
|
||||
parser.add_argument("--output", default="calico_netpol_report.json")
|
||||
args = parser.parse_args()
|
||||
|
||||
report = {"generated_at": datetime.utcnow().isoformat(), "results": {}}
|
||||
|
||||
if args.action in ("audit", "full") and args.audit:
|
||||
result = audit_network_policies(args.audit)
|
||||
report["results"]["audit"] = result
|
||||
print(f"[+] Audit: {len(result['findings'])} findings across {result['total_policies']} policies")
|
||||
|
||||
if args.action in ("generate", "full") and args.namespace:
|
||||
policies = [
|
||||
generate_default_deny(args.namespace),
|
||||
generate_allow_dns_egress(args.namespace),
|
||||
]
|
||||
if args.app:
|
||||
policies.append(generate_app_policy(args.namespace, args.app))
|
||||
report["results"]["generated"] = policies
|
||||
print(f"[+] Generated {len(policies)} policies for {args.namespace}")
|
||||
|
||||
if args.action in ("check", "full"):
|
||||
result = check_unprotected_namespaces()
|
||||
report["results"]["unprotected"] = result
|
||||
print(f"[+] Unprotected namespaces: {result.get('unprotected', [])}")
|
||||
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2, default=str)
|
||||
print(f"[+] Report saved to {args.output}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user