feat(cache): redis TLS support (#1297)

This commit is contained in:
Taufik Mulyana
2022-01-18 20:16:00 +07:00
committed by GitHub
parent 02c3c3659d
commit cabd18daae
7 changed files with 108 additions and 6 deletions

View File

@@ -41,3 +41,14 @@ Two options:
```
$ trivy server --cache-backend redis://localhost:6379
```
Trivy also support for connecting to Redis using TLS, you only need to specify `--redis-ca` , `--redis-cert` , and `--redis-key` option.
```
$ trivy server --cache-backend redis://localhost:6379 \
--redis-ca /path/to/ca-cert.pem \
--redis-cert /path/to/cert.pem \
--redis-key /path/to/key.pem
```
TLS option for redis is hidden from Trivy command-line flag, but you still can use it.

View File

@@ -166,6 +166,27 @@ var (
EnvVars: []string{"TRIVY_CACHE_BACKEND"},
}
redisBackendCACert = cli.StringFlag{
Name: "redis-ca",
Usage: "redis ca file location, if using redis as cache backend",
EnvVars: []string{"TRIVY_REDIS_BACKEND_CA"},
Hidden: true,
}
redisBackendCert = cli.StringFlag{
Name: "redis-cert",
Usage: "redis certificate file location, if using redis as cache backend",
EnvVars: []string{"TRIVY_REDIS_BACKEND_CERT"},
Hidden: true,
}
redisBackendKey = cli.StringFlag{
Name: "redis-key",
Usage: "redis key file location, if using redis as cache backend",
EnvVars: []string{"TRIVY_REDIS_BACKEND_KEY"},
Hidden: true,
}
ignoreFileFlag = cli.StringFlag{
Name: "ignorefile",
Value: result.DefaultIgnoreFile,
@@ -407,6 +428,9 @@ func NewImageCommand() *cli.Command {
&ignorePolicy,
&listAllPackages,
&cacheBackendFlag,
&redisBackendCACert,
&redisBackendCert,
&redisBackendKey,
&offlineScan,
&insecureFlag,
stringSliceFlag(skipFiles),
@@ -437,6 +461,9 @@ func NewFilesystemCommand() *cli.Command {
&securityChecksFlag,
&ignoreFileFlag,
&cacheBackendFlag,
&redisBackendCACert,
&redisBackendCert,
&redisBackendKey,
&timeoutFlag,
&noProgressFlag,
&ignorePolicy,
@@ -472,6 +499,9 @@ func NewRootfsCommand() *cli.Command {
&securityChecksFlag,
&ignoreFileFlag,
&cacheBackendFlag,
&redisBackendCACert,
&redisBackendCert,
&redisBackendKey,
&timeoutFlag,
&noProgressFlag,
&ignorePolicy,
@@ -510,6 +540,9 @@ func NewRepositoryCommand() *cli.Command {
&securityChecksFlag,
&ignoreFileFlag,
&cacheBackendFlag,
&redisBackendCACert,
&redisBackendCert,
&redisBackendKey,
&timeoutFlag,
&noProgressFlag,
&ignorePolicy,
@@ -582,6 +615,9 @@ func NewServerCommand() *cli.Command {
&downloadDBOnlyFlag,
&resetFlag,
&cacheBackendFlag,
&redisBackendCACert,
&redisBackendCert,
&redisBackendKey,
// original flags
&token,

View File

@@ -94,7 +94,7 @@ func runWithTimeout(ctx context.Context, opt Option, initializeScanner Initializ
func initFSCache(c Option) (cache.Cache, error) {
utils.SetCacheDir(c.CacheDir)
cache, err := operation.NewCache(c.CacheBackend)
cache, err := operation.NewCache(c.CacheOption)
if err != nil {
return operation.Cache{}, xerrors.Errorf("unable to initialize the cache: %w", err)
}

View File

@@ -2,6 +2,7 @@ package operation
import (
"context"
"crypto/tls"
"os"
"strings"
@@ -11,6 +12,7 @@ import (
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy-db/pkg/metadata"
"github.com/aquasecurity/trivy/pkg/commands/option"
"github.com/aquasecurity/trivy/pkg/db"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/policy"
@@ -30,13 +32,27 @@ type Cache struct {
}
// NewCache is the factory method for Cache
func NewCache(backend string) (Cache, error) {
if strings.HasPrefix(backend, "redis://") {
log.Logger.Infof("Redis cache: %s", backend)
options, err := redis.ParseURL(backend)
func NewCache(c option.CacheOption) (Cache, error) {
if strings.HasPrefix(c.CacheBackend, "redis://") {
log.Logger.Infof("Redis cache: %s", c.CacheBackend)
options, err := redis.ParseURL(c.CacheBackend)
if err != nil {
return Cache{}, err
}
if (option.RedisOption{}) != c.RedisOption {
caCert, cert, err := utils.GetTLSConfig(c.RedisCACert, c.RedisCert, c.RedisKey)
if err != nil {
return Cache{}, err
}
options.TLSConfig = &tls.Config{
RootCAs: caCert,
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS12,
}
}
redisCache := cache.NewRedisCache(options)
return Cache{Cache: redisCache}, nil
}

View File

@@ -10,12 +10,25 @@ import (
// CacheOption holds the options for cache
type CacheOption struct {
CacheBackend string
RedisOption
}
// RedisOption holds the options for redis cache
type RedisOption struct {
RedisCACert string
RedisCert string
RedisKey string
}
// NewCacheOption returns an instance of CacheOption
func NewCacheOption(c *cli.Context) CacheOption {
return CacheOption{
CacheBackend: c.String("cache-backend"),
RedisOption: RedisOption{
RedisCACert: c.String("redis-ca"),
RedisCert: c.String("redis-cert"),
RedisKey: c.String("redis-key"),
},
}
}
@@ -27,5 +40,11 @@ func (c *CacheOption) Init() error {
c.CacheBackend != "fs" && c.CacheBackend != "" {
return xerrors.Errorf("unsupported cache backend: %s", c.CacheBackend)
}
// if one of redis option not nil, make sure CA, cert, and key provided
if (RedisOption{}) != c.RedisOption {
if c.RedisCACert == "" || c.RedisCert == "" || c.RedisKey == "" {
return xerrors.Errorf("you must provide CA, cert and key file path when using tls")
}
}
return nil
}

View File

@@ -28,7 +28,7 @@ func run(c Config) (err error) {
// configure cache dir
utils.SetCacheDir(c.CacheDir)
cache, err := operation.NewCache(c.CacheBackend)
cache, err := operation.NewCache(c.CacheOption)
if err != nil {
return xerrors.Errorf("server cache error: %w", err)
}

View File

@@ -1,6 +1,8 @@
package utils
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"os"
@@ -65,3 +67,21 @@ func CopyFile(src, dst string) (int64, error) {
n, err := io.Copy(destination, source)
return n, err
}
// getTLSConfig get tls config from CA, Cert and Key file
func GetTLSConfig(caCertPath, certPath, keyPath string) (*x509.CertPool, tls.Certificate, error) {
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
if err != nil {
return nil, tls.Certificate{}, err
}
caCert, err := os.ReadFile(caCertPath)
if err != nil {
return nil, tls.Certificate{}, err
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
return caCertPool, cert, nil
}