upgrade audit
This commit is contained in:
Executable
+155
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Docker system audit: collect container diagnostics and return as JSON."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
def cmd(args, parse_json=False):
|
||||
try:
|
||||
result = subprocess.run(
|
||||
args,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30,
|
||||
)
|
||||
out = (result.stdout + result.stderr).strip()
|
||||
|
||||
if parse_json:
|
||||
try:
|
||||
return json.loads(out) if out else None
|
||||
except json.JSONDecodeError:
|
||||
return out
|
||||
|
||||
return out
|
||||
|
||||
except Exception as e:
|
||||
return f"ERROR: {e}"
|
||||
|
||||
|
||||
def read_file(path):
|
||||
try:
|
||||
with open(path) as f:
|
||||
return f.read().strip().splitlines()
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
audit = {}
|
||||
|
||||
# Container identity
|
||||
audit["container_id"] = os.environ.get("HOSTNAME")
|
||||
audit["environment"] = dict(os.environ)
|
||||
|
||||
# OS information inside container
|
||||
audit["os_release"] = read_file("/etc/os-release")
|
||||
audit["uname"] = cmd(["uname", "-a"])
|
||||
|
||||
# Installed packages (works for Debian/Ubuntu, Alpine, etc.)
|
||||
audit["packages"] = {}
|
||||
|
||||
if os.path.exists("/etc/alpine-release"):
|
||||
audit["packages"]["manager"] = "apk"
|
||||
audit["packages"]["installed"] = cmd(
|
||||
["apk", "info", "-v"]
|
||||
).splitlines()
|
||||
audit["packages"]["upgradeable"] = cmd(
|
||||
["apk", "version", "-l", "<"]
|
||||
).splitlines()
|
||||
|
||||
elif os.path.exists("/etc/debian_version"):
|
||||
audit["packages"]["manager"] = "dpkg"
|
||||
audit["packages"]["installed"] = cmd(
|
||||
["dpkg-query", "-W", "-f=${Package}-${Version}\n"]
|
||||
).splitlines()
|
||||
|
||||
elif os.path.exists("/etc/redhat-release"):
|
||||
audit["packages"]["manager"] = "rpm"
|
||||
audit["packages"]["installed"] = cmd(
|
||||
["rpm", "-qa"]
|
||||
).splitlines()
|
||||
|
||||
# Docker engine information
|
||||
audit["docker_version"] = cmd(
|
||||
["docker", "version", "--format", "{{json .}}"],
|
||||
parse_json=True,
|
||||
)
|
||||
|
||||
audit["docker_info"] = cmd(
|
||||
["docker", "info", "--format", "{{json .}}"],
|
||||
parse_json=True,
|
||||
)
|
||||
|
||||
# Containers
|
||||
containers = cmd(
|
||||
["docker", "ps", "-a", "--format", "{{json .}}"],
|
||||
parse_json=True,
|
||||
)
|
||||
|
||||
if isinstance(containers, list):
|
||||
audit["docker_containers"] = containers
|
||||
else:
|
||||
audit["docker_containers"] = []
|
||||
|
||||
# Images
|
||||
audit["docker_images"] = cmd(
|
||||
["docker", "images", "--format", "{{json .}}"],
|
||||
parse_json=True,
|
||||
)
|
||||
|
||||
# Runtime stats
|
||||
audit["docker_stats"] = cmd(
|
||||
[
|
||||
"docker",
|
||||
"stats",
|
||||
"--no-stream",
|
||||
"--format",
|
||||
"table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}",
|
||||
]
|
||||
)
|
||||
|
||||
# Container logs
|
||||
logs = {}
|
||||
|
||||
for c in audit["docker_containers"]:
|
||||
name = c.get("Names") or c.get("ID")
|
||||
|
||||
if not name:
|
||||
continue
|
||||
|
||||
logs[name] = cmd(
|
||||
[
|
||||
"docker",
|
||||
"logs",
|
||||
"--tail",
|
||||
"100",
|
||||
name,
|
||||
]
|
||||
)
|
||||
|
||||
audit["docker_logs"] = logs
|
||||
|
||||
# SSH config if present
|
||||
audit["sshd_config"] = cmd(
|
||||
["sshd", "-T"]
|
||||
).splitlines()
|
||||
|
||||
# Users
|
||||
audit["passwd"] = read_file("/etc/passwd")
|
||||
|
||||
# Runtime info
|
||||
audit["uptime"] = cmd(["uptime"])
|
||||
|
||||
# cgroups (useful in Docker)
|
||||
audit["cgroup"] = read_file("/proc/self/cgroup")
|
||||
|
||||
# Mounted filesystems
|
||||
audit["mounts"] = cmd(["mount"]).splitlines()
|
||||
|
||||
print(json.dumps(audit, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user