Skip to content

Commit

Permalink
new checkpoint : Only put necessary files (goodwithtech#54)
Browse files Browse the repository at this point in the history
* use goodwithtech/deckoder and unuse xerrors

* check unnecessary files

* update ci goversion

* fix lint

* improve how to check required directory

* create DockerOption from cli args

* add scan test
  • Loading branch information
tomoyamachi authored Sep 16, 2019
1 parent e2a12fa commit fe3c549
Show file tree
Hide file tree
Showing 25 changed files with 299 additions and 106 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defaults: &defaults
working_directory: /go/src/github.com/goodwithtech/dockle
docker:
- image: circleci/golang:1.12.3
- image: circleci/golang:1.13
environment:
GO111MODULE: "on"
steps:
Expand Down
4 changes: 4 additions & 0 deletions CHECKPOINT.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,7 @@ These checkpoints referred to [Linux Best Practices](https://www.cyberciti.biz/t
- http://www.linfo.org/uid.html

> Contrary to popular belief, it is not necessary that each entry in the UID field be unique. However, non-unique UIDs can cause security problems, and thus UIDs should be kept unique across the entire organization.
### DKL-LI-0003: Only put necessary files

Check `.cache`, `tmp` and so on directories.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ $ docker run --rm goodwithtech/dockle:v${DOCKLE_LATEST} [YOUR_IMAGE_NAME]
|| [Dockle Checkpoints for Linux](CHECKPOINT.md#dockerdockle-checkpoints-for-linux) |
| [DKL-LI-0001](CHECKPOINT.md#dkl-li-0001-avoid-empty-password) | Avoid empty password | FATAL
| [DKL-LI-0002](CHECKPOINT.md#dkl-li-0002-be-unique-uidgroups) | Be unique UID/GROUPs | FATAL
| [DKL-LI-0003](CHECKPOINT.md#dkl-li-0003-only-put-necessary-files) | Only put necessary files | INFO
## Level
Expand Down
34 changes: 31 additions & 3 deletions cmd/dockle/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
l "log"
"os"
"time"

"github.com/goodwithtech/dockle/pkg"
"github.com/goodwithtech/dockle/pkg/log"
Expand Down Expand Up @@ -39,12 +40,11 @@ OPTIONS:
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "input",
Value: "",
Usage: "input file path instead of image name",
},
cli.StringSliceFlag{
Name: "ignore, i",
Usage: "A checkpoint to ignore. You can use .dockleignore too.",
Usage: "checkpoints to ignore. You can use .dockleignore too.",
},
cli.StringFlag{
Name: "format, f",
Expand All @@ -57,7 +57,7 @@ OPTIONS:
},
cli.IntFlag{
Name: "exit-code, c",
Usage: "Exit code when alert were found",
Usage: "exit code when alert were found",
Value: 0,
},
cli.StringFlag{
Expand All @@ -69,6 +69,34 @@ OPTIONS:
Name: "debug, d",
Usage: "debug mode",
},

// Registry flag
cli.DurationFlag{
Name: "timeout, t",
Value: time.Second * 90,
Usage: "docker timeout. e.g) 5s, 5m...",
},
cli.StringFlag{
Name: "authurl",
Usage: "registry authenticate url",
},
cli.StringFlag{
Name: "username",
Usage: "registry login username",
},
cli.StringFlag{
Name: "password",
Usage: "registry login password. Using --password via CLI is insecure.",
},
cli.BoolFlag{
Name: "insecure",
Usage: "registry connect insecure",
},
cli.BoolTFlag{
Name: "nonssl",
Usage: "registry connect without ssl",
},

cli.StringFlag{
Name: "cache-dir",
Usage: "cache directory",
Expand Down
7 changes: 2 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ module github.com/goodwithtech/dockle
go 1.12

require (
github.com/caarlos0/env/v6 v6.0.0
github.com/d4l3k/messagediff v1.2.2-0.20180726183240-b9e99b2f9263
github.com/docker/go-connections v0.4.0
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f // indirect
github.com/genuinetools/reg v0.16.0
github.com/knqyf263/fanal v0.0.0-20190528042547-07e27879b658
github.com/goodwithtech/deckoder v0.0.0-20190914200440-2d3347be7dd3
github.com/google/go-cmp v0.3.0
github.com/moul/http2curl v1.0.0 // indirect
github.com/parnurzeal/gorequest v0.2.15
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect
Expand All @@ -18,9 +18,6 @@ require (
go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.10.0
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522
)

replace github.com/genuinetools/reg => github.com/tomoyamachi/reg v0.16.1-0.20190706172545-2a2250fd7c00

replace github.com/knqyf263/fanal => github.com/goodwithtech/fanal v0.0.0-20190706194703-57e52a04aa8b
16 changes: 2 additions & 14 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLM
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/caarlos0/env/v6 v6.0.0 h1:NZt6FAoB8ieKO5lEwRdwCzYxWFx7ZYF2R7UcoyaWtyc=
github.com/caarlos0/env/v6 v6.0.0/go.mod h1:+wdyOmtjoZIW2GJOc2OYa5NoOFuWD/bIpWqm30NgtRk=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
Expand All @@ -34,7 +32,6 @@ github.com/d4l3k/messagediff v1.2.2-0.20180726183240-b9e99b2f9263/go.mod h1:Oozb
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/cli v0.0.0-20180920165730-54c19e67f69c h1:QlAVcyoF7QQVN7zV+xYBjgwtRVlRU3WCTCpb2mcqQrM=
github.com/docker/cli v0.0.0-20180920165730-54c19e67f69c/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
Expand Down Expand Up @@ -83,8 +80,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/goodwithtech/fanal v0.0.0-20190706194703-57e52a04aa8b h1:m9uq6kdq961meE/XEnI812saPRLPZIPEPc3WKMAAAJo=
github.com/goodwithtech/fanal v0.0.0-20190706194703-57e52a04aa8b/go.mod h1:kdmitQCmUcpPs1JZA3/kBuxu0AeN9OnVLl7SRkPUoGU=
github.com/goodwithtech/deckoder v0.0.0-20190914200440-2d3347be7dd3 h1:fHsxZkhj9PBDtNwo/6x+uOGe0TZajp/nVLFn7RgbVag=
github.com/goodwithtech/deckoder v0.0.0-20190914200440-2d3347be7dd3/go.mod h1:+OL/nA/BaFd697EYdEP111Opjo26rf2a6CUtO671V8s=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
Expand All @@ -111,19 +108,13 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/knqyf263/berkeleydb v0.0.0-20190501065933-fafe01fb9662/go.mod h1:bu1CcN4tUtoRcI/B/RFHhxMNKFHVq/c3SV+UTyduoXg=
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d/go.mod h1:o8sgWoz3JADecfc/cTYD92/Et1yMqMy0utV1z+VaZao=
github.com/knqyf263/go-dep-parser v0.0.0-20190521150559-1ef8521d17a0 h1:DOQ2UbTciy48dV9vpZ25BOiShrWIWZwBdMOy7SD1Wow=
github.com/knqyf263/go-dep-parser v0.0.0-20190521150559-1ef8521d17a0/go.mod h1:gSiqSkOFPstUZu/qZ4wnNJS69PtQQnPl397vxKHJ5mQ=
github.com/knqyf263/go-rpmdb v0.0.0-20190501070121-10a1c42a10dc/go.mod h1:MrSSvdMpTSymaQWk1yFr9sxFSyQmKMj6jkbvGrchBV8=
github.com/knqyf263/nested v0.0.1 h1:Sv26CegUMhjt19zqbBKntjwESdxe5hxVPSk0+AKjdUc=
github.com/knqyf263/nested v0.0.1/go.mod h1:zwhsIhMkBg90DTOJQvxPkKIypEHPYkgWHs4gybdlUmk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
Expand Down Expand Up @@ -259,9 +250,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190503185657-3b6f9c0030f7/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522 h1:bhOzK9QyoD0ogCnFro1m2mz41+Ib0oOhfJnBp5MR4K4=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
Expand Down
4 changes: 3 additions & 1 deletion pkg/assessor/assessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package assessor
import (
"os"

"github.com/goodwithtech/dockle/pkg/assessor/cache"
"github.com/goodwithtech/dockle/pkg/assessor/privilege"

"github.com/goodwithtech/dockle/pkg/assessor/contentTrust"
Expand All @@ -14,9 +15,9 @@ import (
"github.com/goodwithtech/dockle/pkg/assessor/passwd"
"github.com/goodwithtech/dockle/pkg/assessor/user"

"github.com/goodwithtech/deckoder/extractor"
"github.com/goodwithtech/dockle/pkg/log"
"github.com/goodwithtech/dockle/pkg/types"
"github.com/knqyf263/fanal/extractor"
)

var assessors []Assessor
Expand All @@ -36,6 +37,7 @@ func init() {
RegisterAssessor(credential.CredentialAssessor{})
RegisterAssessor(manifest.ManifestAssessor{})
RegisterAssessor(contentTrust.ContentTrustAssessor{})
RegisterAssessor(cache.CacheAssessor{})
}

func GetAssessments(files extractor.FileMap) (assessments []*types.Assessment) {
Expand Down
86 changes: 86 additions & 0 deletions pkg/assessor/cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package cache

import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/goodwithtech/deckoder/utils"

"github.com/goodwithtech/deckoder/extractor"
"github.com/goodwithtech/dockle/pkg/log"
"github.com/goodwithtech/dockle/pkg/types"
)

var (
reqFiles = []string{"Dockerfile", "docker-compose.yml", ".vimrc"}
// Directory ends "/" separator
reqDirs = []string{".cache/", "tmp/", ".git/", ".vscode/", ".idea/", ".npm/"}
uncontrollableDirs = []string{"node_modules/", "vendor/"}
detectedDir = map[string]struct{}{}
)

type CacheAssessor struct{}

func (a CacheAssessor) Assess(fileMap extractor.FileMap) ([]*types.Assessment, error) {
log.Logger.Debug("Start scan : cache files")
assesses := []*types.Assessment{}
for filename := range fileMap {
fileBase := filepath.Base(filename)
dirName := filepath.Dir(filename)
dirBase := filepath.Base(dirName)

// match Directory
if utils.StringInSlice(dirBase+"/", reqDirs) || utils.StringInSlice(dirName+"/", reqDirs) {
if _, ok := detectedDir[dirName]; ok {
continue
}
detectedDir[dirName] = struct{}{}

// Skip uncontrollable dependency directory e.g) npm : node_modules, php: composer
if inIgnoreDir(filename) {
continue
}

assesses = append(
assesses,
&types.Assessment{
Type: types.InfoDeletableFiles,
Filename: dirName,
Desc: fmt.Sprintf("Suspitcious directory : %s ", dirName),
})

}

// match File
if utils.StringInSlice(filename, reqFiles) || utils.StringInSlice(fileBase, reqFiles) {
assesses = append(
assesses,
&types.Assessment{
Type: types.InfoDeletableFiles,
Filename: filename,
Desc: fmt.Sprintf("unnecessary file : %s ", filename),
})
}
}
return assesses, nil
}

// check and register uncontrollable directory e.g) npm : node_modules, php: composer
func inIgnoreDir(filename string) bool {
for _, ignoreDir := range uncontrollableDirs {
if strings.Contains(filename, ignoreDir) {
return true
}
}
return false
}

func (a CacheAssessor) RequiredFiles() []string {
return append(reqFiles, reqDirs...)
}

func (a CacheAssessor) RequiredPermissions() []os.FileMode {
return []os.FileMode{}
}
2 changes: 1 addition & 1 deletion pkg/assessor/contentTrust/contentTrust.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package contentTrust
import (
"os"

"github.com/goodwithtech/deckoder/extractor"
"github.com/goodwithtech/dockle/pkg/log"
"github.com/goodwithtech/dockle/pkg/types"
"github.com/knqyf263/fanal/extractor"
)

type ContentTrustAssessor struct{}
Expand Down
2 changes: 1 addition & 1 deletion pkg/assessor/credential/credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (

"github.com/goodwithtech/dockle/pkg/log"

"github.com/goodwithtech/deckoder/extractor"
"github.com/goodwithtech/dockle/pkg/types"
"github.com/knqyf263/fanal/extractor"
)

type CredentialAssessor struct{}
Expand Down
2 changes: 1 addition & 1 deletion pkg/assessor/group/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

"github.com/goodwithtech/dockle/pkg/types"

"github.com/knqyf263/fanal/extractor"
"github.com/goodwithtech/deckoder/extractor"
)

type GroupAssessor struct{}
Expand Down
2 changes: 1 addition & 1 deletion pkg/assessor/hosts/hosts.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package hosts
import (
"os"

"github.com/goodwithtech/deckoder/extractor"
"github.com/goodwithtech/dockle/pkg/log"
"github.com/goodwithtech/dockle/pkg/types"
"github.com/knqyf263/fanal/extractor"
)

type HostsAssessor struct{}
Expand Down
10 changes: 5 additions & 5 deletions pkg/assessor/manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ package manifest

import (
"encoding/json"
"errors"
"fmt"
"os"
"strings"
"time"

"github.com/goodwithtech/dockle/pkg/log"

"github.com/goodwithtech/deckoder/extractor"
"github.com/goodwithtech/dockle/pkg/types"
"github.com/knqyf263/fanal/extractor"
"golang.org/x/xerrors"
)

type ManifestAssessor struct{}
Expand All @@ -24,14 +24,14 @@ func (a ManifestAssessor) Assess(fileMap extractor.FileMap) (assesses []*types.A
log.Logger.Debug("Scan start : config file")
file, ok := fileMap["/config"]
if !ok {
return nil, xerrors.New("config json file doesn't exist")
return nil, errors.New("config json file doesn't exist")
}

var d types.Image

err = json.Unmarshal(file.Body, &d)
if err != nil {
return nil, xerrors.New("Fail to parse docker config file.")
return nil, errors.New("Fail to parse docker config file.")
}

return checkAssessments(d)
Expand Down Expand Up @@ -84,7 +84,7 @@ func checkAssessments(img types.Image) (assesses []*types.Assessment, err error)
case results := <-assessesCh:
assesses = append(assesses, results...)
case <-timeout:
return nil, xerrors.New("timeout: manifest assessor")
return nil, errors.New("timeout: manifest assessor")
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/assessor/passwd/passwd.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

"github.com/goodwithtech/dockle/pkg/types"

"github.com/knqyf263/fanal/extractor"
"github.com/goodwithtech/deckoder/extractor"
)

type PasswdAssessor struct{}
Expand Down
2 changes: 1 addition & 1 deletion pkg/assessor/privilege/suid.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"os"
"strings"

"github.com/goodwithtech/deckoder/extractor"
"github.com/goodwithtech/dockle/pkg/types"
"github.com/knqyf263/fanal/extractor"
)

type PrivilegeAssessor struct{}
Expand Down
Loading

0 comments on commit fe3c549

Please sign in to comment.