Skip to content

Commit

Permalink
Security audit check (treeverse#2776)
Browse files Browse the repository at this point in the history
  • Loading branch information
nopcoder authored Dec 12, 2021
1 parent 9685485 commit 923a649
Show file tree
Hide file tree
Showing 19 changed files with 611 additions and 6 deletions.
4 changes: 4 additions & 0 deletions api/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,10 @@ components:
properties:
version:
type: string
upgrade_recommended:
type: boolean
upgrade_url:
type: string

ActionRun:
type: object
Expand Down
6 changes: 6 additions & 0 deletions clients/java/api/openapi.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions clients/java/docs/VersionConfig.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions clients/python/docs/VersionConfig.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions clients/python/lakefs_client/model/version_config.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion cmd/lakefs/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"io"
"math/rand"
"net"
"net/http"
"net/url"
Expand Down Expand Up @@ -164,6 +165,15 @@ var runCmd = &cobra.Command{
c.SetHooksHandler(actionsService)
defer actionsService.Stop()

auditChecker := version.NewDefaultAuditChecker(cfg.GetSecurityAuditCheckURL())
defer auditChecker.Close()
if version.Version != version.UnreleasedVersion {
const maxSecondsToJitter = 12 * 60 * 60 // 12h in seconds
jitter := time.Duration(rand.Int63n(maxSecondsToJitter)) * time.Second //nolint:gosec
interval := cfg.GetSecurityAuditCheckInterval() + jitter
auditChecker.StartPeriodicCheck(ctx, interval, logger)
}

allowForeign, err := cmd.Flags().GetBool(mismatchedReposFlagName)
if err != nil {
fmt.Printf("%s: %s\n", mismatchedReposFlagName, err)
Expand Down Expand Up @@ -192,6 +202,7 @@ var runCmd = &cobra.Command{
bufferedCollector,
cloudMetadataProvider,
actionsService,
auditChecker,
logger.WithField("service", "api_gateway"),
cfg.GetS3GatewayDomainNames(),
)
Expand Down Expand Up @@ -405,7 +416,7 @@ func init() {
runCmd.Flags().BoolP(mismatchedReposFlagName, "m", false, "Allow repositories from other object store types")
if err := runCmd.Flags().MarkHidden(mismatchedReposFlagName); err != nil {
// (internal error)
fmt.Fprint(os.Stderr, err)
_, _ = fmt.Fprint(os.Stderr, err)
os.Exit(internalErrorCode)
}
}
1 change: 1 addition & 0 deletions docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ This reference uses `.` to denote the nesting of values.
* `gateways.s3.region` `(string : "us-east-1")` - AWS region we're pretending to be. Should match the region configuration used in AWS SDK clients
* `gateways.s3.fallback_url` `(string)` - If specified, requests with a non-existing repository will be forwarded to this url. This can be useful for using lakeFS side-by-side with S3, with the URL pointing at an [S3Proxy](https://github.com/gaul/s3proxy) instance.
* `stats.enabled` `(boolean : true)` - Whether or not to periodically collect anonymous usage statistics
* `security.audit_check_interval` `(duration : 12h)` - Duration in which we check for security audit
{: .ref-list }

## Using Environment Variables
Expand Down
7 changes: 7 additions & 0 deletions pkg/api/audit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package api

import "github.com/treeverse/lakefs/pkg/version"

type AuditChecker interface {
LastCheck() (*version.AuditResponse, error)
}
23 changes: 22 additions & 1 deletion pkg/api/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ type Controller struct {
Collector stats.Collector
CloudMetadataProvider cloud.MetadataProvider
Actions actionsHandler
AuditChecker AuditChecker
Logger logging.Logger
}

Expand Down Expand Up @@ -2936,7 +2937,25 @@ func (c *Controller) GetLakeFSVersion(w http.ResponseWriter, r *http.Request) {
writeError(w, http.StatusUnauthorized, ErrAuthenticatingRequest)
return
}
writeResponse(w, http.StatusOK, VersionConfig{Version: swag.String(version.Version)})
// set upgrade recommended based on last security audit check
var (
upgradeRecommended *bool
upgradeURL *string
)
lastCheck, _ := c.AuditChecker.LastCheck()
if lastCheck != nil {
recommendedURL := lastCheck.UpgradeRecommendedURL()
if recommendedURL != "" {
upgradeRecommended = swag.Bool(true)
upgradeURL = swag.String(recommendedURL)
}
}

writeResponse(w, http.StatusOK, VersionConfig{
UpgradeRecommended: upgradeRecommended,
UpgradeUrl: upgradeURL,
Version: swag.String(version.Version),
})
}

func IsStatusCodeOK(statusCode int) bool {
Expand Down Expand Up @@ -3078,6 +3097,7 @@ func NewController(
collector stats.Collector,
cloudMetadataProvider cloud.MetadataProvider,
actions actionsHandler,
auditChecker AuditChecker,
logger logging.Logger,
) *Controller {
return &Controller{
Expand All @@ -3091,6 +3111,7 @@ func NewController(
Collector: collector,
CloudMetadataProvider: cloudMetadataProvider,
Actions: actions,
AuditChecker: auditChecker,
Logger: logger,
}
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func Serve(
collector stats.Collector,
cloudMetadataProvider cloud.MetadataProvider,
actions actionsHandler,
auditChecker AuditChecker,
logger logging.Logger,
gatewayDomains []string,
) http.Handler {
Expand Down Expand Up @@ -80,6 +81,7 @@ func Serve(
collector,
cloudMetadataProvider,
actions,
auditChecker,
logger,
)
HandlerFromMuxWithBaseURL(controller, apiRouter, BaseURL)
Expand Down
4 changes: 4 additions & 0 deletions pkg/api/serve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/treeverse/lakefs/pkg/logging"
"github.com/treeverse/lakefs/pkg/stats"
"github.com/treeverse/lakefs/pkg/testutil"
"github.com/treeverse/lakefs/pkg/version"
)

const (
Expand Down Expand Up @@ -110,6 +111,8 @@ func setupHandler(t testing.TB, blockstoreType string, opts ...testutil.GetDBOpt
_ = c.Close()
})

auditChecker := version.NewDefaultAuditChecker(cfg.GetSecurityAuditCheckURL())

handler := api.Serve(
cfg,
c,
Expand All @@ -121,6 +124,7 @@ func setupHandler(t testing.TB, blockstoreType string, opts ...testutil.GetDBOpt
collector,
nil,
actionsService,
auditChecker,
logging.Default(),
nil,
)
Expand Down
17 changes: 17 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ const (
StatsEnabledKey = "stats.enabled"
StatsAddressKey = "stats.address"
StatsFlushIntervalKey = "stats.flush_interval"

SecurityAuditCheckIntervalKey = "security.audit_check_interval"
DefaultSecurityAuditCheckInterval = 12 * time.Hour

SecurityAuditCheckURLKey = "security.audit_check_url"
DefaultSecurityAuditCheckURL = "https://audit.lakefs.io/audit"
)

func setDefaults() {
Expand Down Expand Up @@ -192,6 +198,9 @@ func setDefaults() {

viper.SetDefault(BlockstoreAzureTryTimeoutKey, DefaultAzureTryTimeout)
viper.SetDefault(BlockstoreAzureAuthMethod, DefaultAzureAuthMethod)

viper.SetDefault(SecurityAuditCheckIntervalKey, DefaultSecurityAuditCheckInterval)
viper.SetDefault(SecurityAuditCheckURLKey, DefaultSecurityAuditCheckURL)
}

func reverse(s string) string {
Expand Down Expand Up @@ -429,3 +438,11 @@ func (c *Config) ToLoggerFields() logging.Fields {
func (c *Config) GetLoggingTraceRequestHeaders() bool {
return c.values.Logging.TraceRequestHeaders
}

func (c *Config) GetSecurityAuditCheckInterval() time.Duration {
return c.values.Security.AuditCheckInterval
}

func (c *Config) GetSecurityAuditCheckURL() string {
return c.values.Security.AuditCheckURL
}
4 changes: 4 additions & 0 deletions pkg/config/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,8 @@ type configuration struct {
Installation struct {
FixedID string `mapstructure:"fixed_id"`
}
Security struct {
AuditCheckInterval time.Duration `mapstructure:"audit_check_interval"`
AuditCheckURL string `mapstructure:"audit_check_url"`
} `mapstructure:"security"`
}
Loading

0 comments on commit 923a649

Please sign in to comment.