s0rg/decompose
GitHub: s0rg/decompose
用于 Docker 环境的逆向工程工具,提取容器网络连接并导出为多种可视化格式。
Stars: 126 | Forks: 6
[](https://github.com/s0rg/decompose/actions?query=workflow%3Aci)

[](https://goreportcard.com/report/github.com/s0rg/decompose)

[](https://github.com/s0rg/decompose/blob/master/LICENSE)
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fs0rg%2Fdecompose?ref=badge_shield)
[](go.mod)
[](https://github.com/s0rg/decompose/releases/latest)
[](https://github.com/avelino/awesome-go)

# 分解
用于 Docker 环境的逆向工程工具。
提取 Docker 容器中的所有网络连接并将其导出为:
- [graphviz dot](https://www.graphviz.org/doc/info/lang.html)
- [structurizr dsl](https://github.com/structurizr/dsl)
- [compose yaml](https://github.com/compose-spec/compose-spec/blob/master/spec.md)
- [plant uml](https://github.com/plantuml/plantuml)
- 伪图形树
- json 流
- 统计信息 - 节点、连接和监听端口计数
- 包含列的 CSV:`name`、`listen` 和 `outbounds`
## 缘由
我需要一个工具来可视化和检查庞大(超过 470 个容器)且没有任何方案和文档极其匮乏的 Docker 化遗留系统
## 同类工具
我能找到的最接近的同类工具,但不太符合我的需求:
- [Red5d/docker-autocompose](https://github.com/Red5d/docker-autocompose) - 仅生成 `compose yaml`
- [justone/dockviz](https://github.com/justone/dockviz) - 仅生成 `dot`,链接和端口直接取自 compose 配置(`links` 和 `ports` 部分),因此可能会遗漏部分信息
- [LeoVerto/docker-network-graph](https://github.com/LeoVerto/docker-network-graph) - 与上述非常相似,用 Python 编写
- [weaveworks/scope](https://github.com/weaveworks/scope) - 已弃用,无 CLI
## 特性
- 跨操作系统,它使用不同的策略来获取容器连接:
- 在 **Linux 上以 root 身份运行**是最快的方式,并且适用于所有类型的容器(甚至是基于 `scratch` 的),因为它使用 `nsenter`
- 以非 root 身份或在非 Linux 操作系统上运行时,将尝试在容器内运行 `netstat`,如果失败(例如缺少 `netstat` 二进制文件),则不会收集此类容器的连接
- 单一二进制文件,静态编译的 Unix 风格 `cli`(所有输出转到 stdout,进度信息转到 stderr)
- 生成带有端口的详细连接图
- 保存 `json` 流一次,之后可以任何你想要的方式处理它
- 所有输出格式都经过排序,因此可以放入任何 `vcs` 中以观察变化
- 快速,在大约 5 秒内扫描约 470 个容器和约 4000 个连接
- 基于图拓扑的自动聚类
- 深度检查模式,该模式下容器内进程之间的连接也会被收集和显示
- Unix 套接字连接
- 超过 95% 的测试覆盖率
## 已知限制
- 仅列出已建立和监听的连接(但像 [snapshots.sh](examples/snapshots.sh) 这样的脚本可以解决这个问题)
- `composer-yaml` 并不旨在开箱即用,它可能缺少一些关键信息(即使在 `-full` 模式下),或者可能包含节点之间的循环(删除服务中的 `links` 部分可能有帮助),其主要目的是用于系统概览
- [gephi](https://github.com/gephi/gephi) 无法从生成的 graphviz 加载边,这可以通过任何自动替换工具修复:`sed -i 's/->/ -> /g' myfile.dot`
- Unix 套接字仅在 Linux 的 root 模式下工作,此过程涉及 inode 匹配以查找正确的连接
## 安装
- 适用于 Linux、FreeBSD、macOS 和 Windows 的 [二进制文件 / deb / rpm](https://github.com/s0rg/decompose/releases)
- [Docker 镜像](https://hub.docker.com/r/s0rg/decompose)
## 用法
```
decompose [flags]
-cluster string
json file with clusterization rules, or auto: for auto-clustering, similarity is float in (0.0, 1.0] range
-compress
compress graph
-deep
process-based introspection
-follow string
follow only this container by name(s), comma-separated or from @file
-format string
output format: csv, dot, json, puml, sdsl, stat, tree, yaml (default "json")
-help
show this help
-load value
load json stream, can be used multiple times
-local
skip external hosts
-meta string
json file with metadata for enrichment
-no-loops
remove connection loops (node to itself) from output
-no-orphans
remove orphaned (not connected) nodes from output
-out string
output: filename or "-" for stdout (default "-")
-proto string
protocol to scan: tcp,udp,unix or all (default "all")
-silent
suppress progress messages in stderr
-skip-env string
environment variables name(s) to skip from output, case-independent, comma-separated
-version
show version
```
### 环境变量:
- `DOCKER_HOST` - 连接 URI
- `DOCKER_CERT_PATH` - 包含 key.pem、cert.pm 和 ca.pem 的目录路径
- `DOCKER_TLS_VERIFY` - 启用客户端 TLS 验证
- `IN_DOCKER_PROC_ROOT` - 用于 in-docker 场景 - 主机挂载的 /proc 的根目录
## json 流格式
```
type Item struct {
Name string `json:"name"` // container name
IsExternal bool `json:"is_external"` // this host is external
Image *string `json:"image,omitempty"` // docker image (if any)
Container struct{
Cmd []string `json:"cmd"`
Env []string `json:"env"`
Labels map[string]string `json:"labels"`
} `json:"container"` // container info
Listen map[string][]{
Kind string `json:"kind"` // tcp / udp / unix
Value string `json:"value"`
Local bool `json:"local"` // bound to loopback
} `json:"listen"` // ports with process names
Networks []string `json:"networks"` // network names
Tags []string `json:"tags"` // tags, if meta presents
Volumes []*struct{
Type string `json:"type"`
Src string `json:"src"`
Dst string `json:"dst"`
} `json:"volumes"` // volumes info, only when '-full'
Connected map[string][]string `json:"connected"` // name -> ports slice
}
```
包含完整信息和已填充元数据的单节点示例:
```
{
"name": "foo-1",
"is_external": false,
"image": "repo/foo:latest",
"container": {
"cmd": [
"foo",
"-foo-arg"
],
"env": [
"FOO=1"
],
"labels": {}
},
"listen": {"foo": [
{"kind": "tcp", "value": "80"}
]},
"networks": ["test-net"],
"tags": ["some"],
"volumes": [
{
"type": "volume",
"src": "/var/lib/docker/volumes/foo_1/_data",
"dst": "/data"
},
{
"type": "bind",
"src": "/path/to/foo.conf",
"dst": "/etc/foo.conf"
}
],
"connected": {
"bar-1": [
{"src": "foo", "dst": "[remote]", "port": {"kind": "tcp", "value": "443"}}
]
}
}
```
有关简单的流示例,请参见 [stream.json](examples/stream.json)。
## 元数据格式
要使用详细描述丰富输出,你可以提供额外的 `json` 文件,其中包含元数据,例如:
```
{
"foo": {
"info": "info for foo",
"docs": "https://acme.corp/docs/foo",
"repo": "https://git.acme.corp/foo",
"tags": ["some"]
},
"bar": {
"info": "info for bar",
"tags": ["other", "not-foo"]
}
}
```
使用此文件,`decompose` 可以为每个名称与提供的键之一(如本例中的 `foo-1` 或 `bar1`)匹配的容器丰富输出信息和附加标签。
有关如何从 CSV 创建此类 `json` 的示例,请参见 [csv2meta.py](examples/csv2meta.py);有关元数据样本,请参见 [meta.json](examples/meta.json)。
## 聚类
### 基于规则
你可以通过灵活的规则在 `dot`、`structurizr` 和 `stat` 输出格式中将服务加入到 `clusters` 中。
示例 `json`(顺序很重要):
```
[
{
"name": "cluster-name",
"weight": 1,
"if": ""
},
...
]
```
权重可以省略,如果未指定则等于 `1`。
其中 `` 是 [expr dsl](https://expr-lang.org/docs/Language-Definition),具有包含以下字段的环境对象 `node`:
```
type Node struct {
Listen PortMatcher // port matcher with two methods: `HasAny(...string) bool` and `Has(...string) bool`
Name string // container name
Image string // container image
Cmd string // container cmd
Args []string // container args
Tags []string // tags, if meta present
IsExternal bool // external flag
}
```
参见:[cluster.json](examples/cluster.json) 以获取详细示例。
### 自动
Decompose 提供自动聚类选项,使用 `-cluster auto:` 进行尝试,`similarity` 是 `(0.0, 1.0]` 范围内的浮点数,表示节点必须具有多大的相似端口才能被放入同一个集群(`1.0` - 必须具有所有相等的端口)。
## 示例
保存完整的 json 流:
```
sudo decompose > nodes-1.json
```
获取 `dot` 文件:
```
decompose -format dot > connections.dot
```
获取 tcp 和 udp 连接作为 `dot`:
```
decompose -proto tcp,udp -format dot > tcp.dot
```
合并来自 json 流的图,按协议过滤,跳过远程主机并保存为 `dot`:
```
decompose -local -proto tcp -load "nodes-*.json" -format dot > graph-merged.dot
```
加载 json 流,丰富并保存为 `structurizr dsl`:
```
decompose -load nodes-1.json -meta metadata.json -format sdsl > workspace.dsl
```
保存自动聚类的图,相似度因子为 `0.6`,作为 `structurizr dsl`:
```
decompose -cluster auto:0.6 -format sdsl > workspace.dsl
```
## 结果示例
取自 [redis-cluster](https://github.com/s0rg/redis-cluster-compose) 的方案:
 *它可能太重而无法在浏览器中显示,请使用 `save image as` 并在本地打开*
重现步骤:
```
git clone https://github.com/s0rg/redis-cluster-compose.git
cd redis-cluster-compose
docker compose up -d
```
然后:
```
decompose -format dot | dot -Tsvg > redis-cluster.svg
```
## 许可证
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fs0rg%2Fdecompose?ref=badge_large)
标签:CSV, DevSecOps, Docker, Docker Compose, EVTX分析, Go, Graphviz, JSON, PlantUML, Ruby工具, Structurizr, Web截图, 上游代理, 云资产清单, 依赖关系, 安全防御评估, 实时处理, 容器安全, 容器监控, 文档结构分析, 日志审计, 架构分析, 端口监听, 网络拓扑可视化, 网络连接, 规避防御, 请求拦截, 逆向工程, 配置审计