mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 07:10:41 -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 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"},
|
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{
|
ignoreFileFlag = cli.StringFlag{
|
||||||
Name: "ignorefile",
|
Name: "ignorefile",
|
||||||
Value: result.DefaultIgnoreFile,
|
Value: result.DefaultIgnoreFile,
|
||||||
@@ -407,6 +428,9 @@ func NewImageCommand() *cli.Command {
|
|||||||
&ignorePolicy,
|
&ignorePolicy,
|
||||||
&listAllPackages,
|
&listAllPackages,
|
||||||
&cacheBackendFlag,
|
&cacheBackendFlag,
|
||||||
|
&redisBackendCACert,
|
||||||
|
&redisBackendCert,
|
||||||
|
&redisBackendKey,
|
||||||
&offlineScan,
|
&offlineScan,
|
||||||
&insecureFlag,
|
&insecureFlag,
|
||||||
stringSliceFlag(skipFiles),
|
stringSliceFlag(skipFiles),
|
||||||
@@ -437,6 +461,9 @@ func NewFilesystemCommand() *cli.Command {
|
|||||||
&securityChecksFlag,
|
&securityChecksFlag,
|
||||||
&ignoreFileFlag,
|
&ignoreFileFlag,
|
||||||
&cacheBackendFlag,
|
&cacheBackendFlag,
|
||||||
|
&redisBackendCACert,
|
||||||
|
&redisBackendCert,
|
||||||
|
&redisBackendKey,
|
||||||
&timeoutFlag,
|
&timeoutFlag,
|
||||||
&noProgressFlag,
|
&noProgressFlag,
|
||||||
&ignorePolicy,
|
&ignorePolicy,
|
||||||
@@ -472,6 +499,9 @@ func NewRootfsCommand() *cli.Command {
|
|||||||
&securityChecksFlag,
|
&securityChecksFlag,
|
||||||
&ignoreFileFlag,
|
&ignoreFileFlag,
|
||||||
&cacheBackendFlag,
|
&cacheBackendFlag,
|
||||||
|
&redisBackendCACert,
|
||||||
|
&redisBackendCert,
|
||||||
|
&redisBackendKey,
|
||||||
&timeoutFlag,
|
&timeoutFlag,
|
||||||
&noProgressFlag,
|
&noProgressFlag,
|
||||||
&ignorePolicy,
|
&ignorePolicy,
|
||||||
@@ -510,6 +540,9 @@ func NewRepositoryCommand() *cli.Command {
|
|||||||
&securityChecksFlag,
|
&securityChecksFlag,
|
||||||
&ignoreFileFlag,
|
&ignoreFileFlag,
|
||||||
&cacheBackendFlag,
|
&cacheBackendFlag,
|
||||||
|
&redisBackendCACert,
|
||||||
|
&redisBackendCert,
|
||||||
|
&redisBackendKey,
|
||||||
&timeoutFlag,
|
&timeoutFlag,
|
||||||
&noProgressFlag,
|
&noProgressFlag,
|
||||||
&ignorePolicy,
|
&ignorePolicy,
|
||||||
@@ -582,6 +615,9 @@ func NewServerCommand() *cli.Command {
|
|||||||
&downloadDBOnlyFlag,
|
&downloadDBOnlyFlag,
|
||||||
&resetFlag,
|
&resetFlag,
|
||||||
&cacheBackendFlag,
|
&cacheBackendFlag,
|
||||||
|
&redisBackendCACert,
|
||||||
|
&redisBackendCert,
|
||||||
|
&redisBackendKey,
|
||||||
|
|
||||||
// original flags
|
// original flags
|
||||||
&token,
|
&token,
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ func runWithTimeout(ctx context.Context, opt Option, initializeScanner Initializ
|
|||||||
|
|
||||||
func initFSCache(c Option) (cache.Cache, error) {
|
func initFSCache(c Option) (cache.Cache, error) {
|
||||||
utils.SetCacheDir(c.CacheDir)
|
utils.SetCacheDir(c.CacheDir)
|
||||||
cache, err := operation.NewCache(c.CacheBackend)
|
cache, err := operation.NewCache(c.CacheOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return operation.Cache{}, xerrors.Errorf("unable to initialize the cache: %w", err)
|
return operation.Cache{}, xerrors.Errorf("unable to initialize the cache: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package operation
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -11,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/aquasecurity/fanal/cache"
|
"github.com/aquasecurity/fanal/cache"
|
||||||
"github.com/aquasecurity/trivy-db/pkg/metadata"
|
"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/db"
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
"github.com/aquasecurity/trivy/pkg/policy"
|
"github.com/aquasecurity/trivy/pkg/policy"
|
||||||
@@ -30,13 +32,27 @@ type Cache struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewCache is the factory method for Cache
|
// NewCache is the factory method for Cache
|
||||||
func NewCache(backend string) (Cache, error) {
|
func NewCache(c option.CacheOption) (Cache, error) {
|
||||||
if strings.HasPrefix(backend, "redis://") {
|
if strings.HasPrefix(c.CacheBackend, "redis://") {
|
||||||
log.Logger.Infof("Redis cache: %s", backend)
|
log.Logger.Infof("Redis cache: %s", c.CacheBackend)
|
||||||
options, err := redis.ParseURL(backend)
|
options, err := redis.ParseURL(c.CacheBackend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Cache{}, err
|
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)
|
redisCache := cache.NewRedisCache(options)
|
||||||
return Cache{Cache: redisCache}, nil
|
return Cache{Cache: redisCache}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,25 @@ import (
|
|||||||
// CacheOption holds the options for cache
|
// CacheOption holds the options for cache
|
||||||
type CacheOption struct {
|
type CacheOption struct {
|
||||||
CacheBackend string
|
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
|
// NewCacheOption returns an instance of CacheOption
|
||||||
func NewCacheOption(c *cli.Context) CacheOption {
|
func NewCacheOption(c *cli.Context) CacheOption {
|
||||||
return CacheOption{
|
return CacheOption{
|
||||||
CacheBackend: c.String("cache-backend"),
|
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 != "" {
|
c.CacheBackend != "fs" && c.CacheBackend != "" {
|
||||||
return xerrors.Errorf("unsupported cache backend: %s", 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func run(c Config) (err error) {
|
|||||||
|
|
||||||
// configure cache dir
|
// configure cache dir
|
||||||
utils.SetCacheDir(c.CacheDir)
|
utils.SetCacheDir(c.CacheDir)
|
||||||
cache, err := operation.NewCache(c.CacheBackend)
|
cache, err := operation.NewCache(c.CacheOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("server cache error: %w", err)
|
return xerrors.Errorf("server cache error: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@@ -65,3 +67,21 @@ func CopyFile(src, dst string) (int64, error) {
|
|||||||
n, err := io.Copy(destination, source)
|
n, err := io.Copy(destination, source)
|
||||||
return n, err
|
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