mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-21 23:00:42 -08:00
feat(cache): redis TLS support (#1297)
This commit is contained in:
@@ -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.
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user