Skip to content

Commit c7208b3

Browse files
committed
Support private registry and use cache
1 parent 262fee4 commit c7208b3

File tree

6 files changed

+150
-12
lines changed

6 files changed

+150
-12
lines changed

cache/cache.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package cache
2+
3+
import (
4+
"io"
5+
"os"
6+
"path/filepath"
7+
8+
"golang.org/x/xerrors"
9+
)
10+
11+
func init() {
12+
d, err := os.UserCacheDir()
13+
if err != nil {
14+
d = os.TempDir()
15+
}
16+
cacheDir = filepath.Join(d, "fanal")
17+
os.MkdirAll(cacheDir, os.ModePerm)
18+
}
19+
20+
var (
21+
cacheDir string
22+
)
23+
24+
func Get(key string) io.Reader {
25+
filePath := filepath.Join(cacheDir, key)
26+
f, err := os.Open(filePath)
27+
if err != nil {
28+
return nil
29+
}
30+
return f
31+
}
32+
33+
func Set(key string, file io.Reader) (io.Reader, error) {
34+
filePath := filepath.Join(cacheDir, key)
35+
cacheFile, err := os.Create(filePath)
36+
if err != nil {
37+
return file, xerrors.Errorf("failed to create cache file: %w", err)
38+
}
39+
40+
tee := io.TeeReader(file, cacheFile)
41+
return tee, nil
42+
}

cmd/fanal/main.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ import (
77
"os"
88

99
"github.com/knqyf263/fanal/analyzer"
10-
11-
"golang.org/x/crypto/ssh/terminal"
12-
1310
_ "github.com/knqyf263/fanal/analyzer/os/alpine"
1411
_ "github.com/knqyf263/fanal/analyzer/pkg/apk"
12+
"golang.org/x/crypto/ssh/terminal"
1513
)
1614

1715
func main() {

extractor/docker.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,18 @@ import (
77
"encoding/json"
88
"io"
99
"io/ioutil"
10+
"log"
1011
"path/filepath"
1112
"strings"
1213
"time"
1314

14-
digest "github.com/opencontainers/go-digest"
15-
1615
"github.com/docker/distribution/manifest/schema2"
17-
1816
"github.com/genuinetools/reg/registry"
1917
"github.com/genuinetools/reg/repoutils"
18+
"github.com/knqyf263/fanal/cache"
19+
"github.com/knqyf263/fanal/token"
2020
"github.com/knqyf263/nested"
21+
digest "github.com/opencontainers/go-digest"
2122
"golang.org/x/xerrors"
2223
)
2324

@@ -108,6 +109,7 @@ func (d DockerExtractor) createRegistryClient(ctx context.Context, domain string
108109
if err != nil {
109110
return nil, err
110111
}
112+
auth = token.GetToken(ctx, auth)
111113

112114
// Prevent non-ssl unless explicitly forced
113115
if !d.Option.NonSSL && strings.HasPrefix(auth.ServerAddress, "http:") {
@@ -154,13 +156,21 @@ func (d DockerExtractor) Extract(ctx context.Context, imageName string, filename
154156
for _, ref := range m.Manifest.Layers {
155157
layerIDs = append(layerIDs, string(ref.Digest))
156158
go func(d digest.Digest) {
157-
// Download the layer.
158-
content, err := r.DownloadLayer(ctx, image.Path, d)
159-
if err != nil {
160-
errCh <- xerrors.Errorf("failed to download the layer(%s): %w", d, err)
161-
return
159+
// Use cache
160+
rc := cache.Get(string(d))
161+
if rc == nil {
162+
// Download the layer.
163+
rc, err = r.DownloadLayer(ctx, image.Path, d)
164+
if err != nil {
165+
errCh <- xerrors.Errorf("failed to download the layer(%s): %w", d, err)
166+
return
167+
}
168+
rc, err = cache.Set(string(d), rc)
169+
if err != nil {
170+
log.Print(err)
171+
}
162172
}
163-
gzipReader, err := gzip.NewReader(content)
173+
gzipReader, err := gzip.NewReader(rc)
164174
if err != nil {
165175
errCh <- xerrors.Errorf("invalid gzip: %w", err)
166176
return

go.mod

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@ module github.com/knqyf263/fanal
33
go 1.12
44

55
require (
6+
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect
7+
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect
8+
github.com/aws/aws-sdk-go v1.19.11
69
github.com/docker/distribution v0.0.0-20180920194744-16128bbac47f
10+
github.com/docker/docker v0.0.0-20180924202107-a9c061deec0f
711
github.com/genuinetools/reg v0.16.1-0.20190102165523-d959057b30da
812
github.com/knqyf263/nested v0.0.1
913
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2
1014
github.com/pkg/errors v0.8.1
15+
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e
1116
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5
1217
golang.org/x/xerrors v0.0.0-20190315151331-d61658bd2e18
18+
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
1319
)

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6
55
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
66
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
77
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
8+
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
9+
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
10+
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
11+
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
12+
github.com/aws/aws-sdk-go v1.19.11 h1:tqaTGER6Byw3QvsjGW0p018U2UOqaJPeJuzoaF7jjoQ=
13+
github.com/aws/aws-sdk-go v1.19.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
814
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
915
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
1016
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -57,6 +63,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.5.0 h1:WcmKMm43DR7RdtlkEXQJyo5ws8iTp98
5763
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
5864
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
5965
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
66+
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
67+
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
6068
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
6169
github.com/knqyf263/nested v0.0.1 h1:Sv26CegUMhjt19zqbBKntjwESdxe5hxVPSk0+AKjdUc=
6270
github.com/knqyf263/nested v0.0.1/go.mod h1:zwhsIhMkBg90DTOJQvxPkKIypEHPYkgWHs4gybdlUmk=
@@ -125,6 +133,8 @@ google.golang.org/grpc v1.15.0 h1:Az/KuahOM4NAidTEuJCv/RonAA7rYsTPkqXVjr+8OOw=
125133
google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
126134
gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=
127135
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
136+
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
137+
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
128138
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
129139
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
130140
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=

token/token.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package token
2+
3+
import (
4+
"context"
5+
"encoding/base64"
6+
"strings"
7+
8+
"github.com/prometheus/common/log"
9+
10+
"golang.org/x/xerrors"
11+
12+
"github.com/aws/aws-sdk-go/aws/session"
13+
"github.com/aws/aws-sdk-go/service/ecr"
14+
"github.com/docker/docker/api/types"
15+
)
16+
17+
const (
18+
ecrURL = "amazonaws.com"
19+
gcrURL = "grc.io"
20+
)
21+
22+
func GetToken(ctx context.Context, auth types.AuthConfig) types.AuthConfig {
23+
if auth.Username != "" || auth.Password != "" {
24+
return auth
25+
}
26+
27+
var username, password string
28+
var err error
29+
30+
switch {
31+
case strings.HasSuffix(auth.ServerAddress, ecrURL):
32+
username, password, err = GetECRAuthorizationToken(ctx)
33+
case strings.HasSuffix(auth.ServerAddress, gcrURL):
34+
username, password, err = GetGCRAuthorizationToken(ctx)
35+
}
36+
if err != nil {
37+
log.Debugf("failed to get token: %w", err)
38+
}
39+
auth.Username = username
40+
auth.Password = password
41+
return auth
42+
}
43+
44+
func GetECRAuthorizationToken(ctx context.Context) (username, password string, err error) {
45+
sess := session.Must(session.NewSessionWithOptions(session.Options{
46+
SharedConfigState: session.SharedConfigEnable,
47+
}))
48+
svc := ecr.New(sess)
49+
input := &ecr.GetAuthorizationTokenInput{}
50+
51+
result, err := svc.GetAuthorizationTokenWithContext(ctx, input)
52+
if err != nil {
53+
return "", "", xerrors.Errorf("failed to get authorization token: %w", err)
54+
}
55+
56+
for _, data := range result.AuthorizationData {
57+
b, err := base64.StdEncoding.DecodeString(*data.AuthorizationToken)
58+
if err != nil {
59+
return "", "", xerrors.Errorf("base64 decode failed: %w", err)
60+
}
61+
// e.g. AWS:eyJwYXlsb2...
62+
split := strings.SplitN(string(b), ":", 2)
63+
if len(split) == 2 {
64+
return split[0], split[1], nil
65+
}
66+
}
67+
return "", "", nil
68+
}
69+
70+
func GetGCRAuthorizationToken(ctx context.Context) (username, password string, err error) {
71+
return "", "", nil
72+
}

0 commit comments

Comments
 (0)