From b7e9a85be0f637f90e9aecba49da301bb151a716 Mon Sep 17 00:00:00 2001 From: yusing Date: Mon, 24 Feb 2025 06:47:07 +0800 Subject: [PATCH] implement docker image blacklist --- internal/docker/container.go | 3 +- internal/docker/container_helper.go | 56 +++++++++++++-------------- internal/docker/image_blacklist.go | 59 +++++++++++++++++++++++++++++ internal/route/route.go | 2 +- 4 files changed, 89 insertions(+), 31 deletions(-) create mode 100644 internal/docker/image_blacklist.go diff --git a/internal/docker/container.go b/internal/docker/container.go index 9db5625..ac93325 100644 --- a/internal/docker/container.go +++ b/internal/docker/container.go @@ -51,7 +51,7 @@ var DummyContainer = new(Container) func FromDocker(c *container.Summary, dockerHost string) (res *Container) { isExplicit := false - helper := containerHelper{c} + helper := containerHelper{Summary: c} for lbl := range c.Labels { if strings.HasPrefix(lbl, NSProxy+".") { isExplicit = true @@ -63,7 +63,6 @@ func FromDocker(c *container.Summary, dockerHost string) (res *Container) { DockerHost: dockerHost, ContainerName: helper.getName(), ContainerID: c.ID, - ImageName: helper.getImageName(), Labels: c.Labels, diff --git a/internal/docker/container_helper.go b/internal/docker/container_helper.go index f886135..d78cd21 100644 --- a/internal/docker/container_helper.go +++ b/internal/docker/container_helper.go @@ -7,9 +7,17 @@ import ( "github.com/yusing/go-proxy/internal/utils/strutils" ) -type containerHelper struct { - *container.Summary -} +type ( + containerHelper struct { + *container.Summary + image *ContainerImage + } + ContainerImage struct { + Author string + Name string + Tag string + } +) // getDeleteLabel gets the value of a label and then deletes it from the container. // If the label does not exist, an empty string is returned. @@ -32,10 +40,21 @@ func (c containerHelper) getName() string { return strings.TrimPrefix(c.Names[0], "/") } -func (c containerHelper) getImageName() string { +func (c containerHelper) parseImage() *ContainerImage { colonSep := strutils.SplitRune(c.Image, ':') slashSep := strutils.SplitRune(colonSep[0], '/') - return slashSep[len(slashSep)-1] + im := new(ContainerImage) + if len(slashSep) > 1 { + im.Author = slashSep[len(slashSep)-1] + im.Name = strings.Join(slashSep[:len(slashSep)-1], "/") + } else { + im.Author = "library" + im.Name = colonSep[0] + } + if len(colonSep) > 1 { + im.Tag = colonSep[1] + } + return im } func (c containerHelper) getPublicPortMapping() PortMapping { @@ -57,28 +76,9 @@ func (c containerHelper) getPrivatePortMapping() PortMapping { return res } -var databaseMPs = map[string]struct{}{ - "/var/lib/postgresql/data": {}, - "/var/lib/mysql": {}, - "/var/lib/mongodb": {}, - "/var/lib/mariadb": {}, - "/var/lib/memcached": {}, - "/var/lib/rabbitmq": {}, -} - -func (c containerHelper) isDatabase() bool { - for _, m := range c.Mounts { - if _, ok := databaseMPs[m.Destination]; ok { - return true - } +func (c containerHelper) IsBlacklisted() bool { + if c.image == nil { + c.image = c.parseImage() } - - for _, v := range c.Ports { - switch v.PrivatePort { - // postgres, mysql or mariadb, redis, memcached, mongodb - case 5432, 3306, 6379, 11211, 27017: - return true - } - } - return false + return c.image.IsBlacklisted() } diff --git a/internal/docker/image_blacklist.go b/internal/docker/image_blacklist.go new file mode 100644 index 0000000..a7a7c3b --- /dev/null +++ b/internal/docker/image_blacklist.go @@ -0,0 +1,59 @@ +package docker + +var imageBlacklist = map[string]struct{}{ + // pure databases without UI + "postgres": {}, + "mysql": {}, + "mariadb": {}, + "redis": {}, + "memcached": {}, + "mongo": {}, + "rabbitmq": {}, + "couchdb": {}, + "neo4j": {}, + "telegraf": {}, + + // search engines, usually used for internal services + "elasticsearch": {}, + "meilisearch": {}, + "kibana": {}, + "solr": {}, +} + +var imageBlacklistFullname = map[string]struct{}{ + // headless browsers + "gcr.io/zenika-hub/alpine-chrome": {}, + "eu.gcr.io/zenika-hub/alpine-chrome": {}, + "us.gcr.io/zenika-hub/alpine-chrome": {}, + "asia.gcr.io/zenika-hub/alpine-chrome": {}, + + // image update watchers + "watchtower": {}, + "getwud/wud": {}, +} + +var authorBlacklist = map[string]struct{}{ + // headless browsers + "selenium": {}, + "browserless": {}, + "zenika": {}, + + "zabbix": {}, + + // docker + "moby": {}, + "docker": {}, +} + +func (image *ContainerImage) IsBlacklisted() bool { + _, ok := imageBlacklist[image.Name] + if ok { + return true + } + _, ok = imageBlacklistFullname[image.Author+":"+image.Name] + if ok { + return true + } + _, ok = authorBlacklist[image.Author] + return ok +} diff --git a/internal/route/route.go b/internal/route/route.go index 2fbb543..6902341 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -215,7 +215,7 @@ func (r *Route) ShouldExclude() bool { return true case r.IsZeroPort() && !r.UseIdleWatcher(): return true - case r.Container.IsDatabase && !r.Container.IsExplicit: + case !r.Container.IsExplicit && r.Container.IsBlacklisted(): return true case strings.HasPrefix(r.Container.ContainerName, "buildx_"): return true