2965dc6a1a
Fix numerous go-getter security issues: - Add timeouts to http, git, and hg operations to prevent DoS - Add size limit to http to prevent resource exhaustion - Disable following symlinks in both artifacts and `job run` - Stop performing initial HEAD request to avoid file corruption on retries and DoS opportunities. **Approach** Since Nomad has no ability to differentiate a DoS-via-large-artifact vs a legitimate workload, all of the new limits are configurable at the client agent level. The max size of HTTP downloads is also exposed as a node attribute so that if some workloads have large artifacts they can specify a high limit in their jobspecs. In the future all of this plumbing could be extended to enable/disable specific getters or artifact downloading entirely on a per-node basis.
75 lines
1.7 KiB
Go
75 lines
1.7 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/dustin/go-humanize"
|
|
"github.com/hashicorp/nomad/nomad/structs/config"
|
|
)
|
|
|
|
// ArtifactConfig is the internal readonly copy of the client agent's
|
|
// ArtifactConfig.
|
|
type ArtifactConfig struct {
|
|
HTTPReadTimeout time.Duration
|
|
HTTPMaxBytes int64
|
|
|
|
GCSTimeout time.Duration
|
|
GitTimeout time.Duration
|
|
HgTimeout time.Duration
|
|
S3Timeout time.Duration
|
|
}
|
|
|
|
// ArtifactConfigFromAgent creates a new internal readonly copy of the client
|
|
// agent's ArtifactConfig. The config should have already been validated.
|
|
func ArtifactConfigFromAgent(c *config.ArtifactConfig) (*ArtifactConfig, error) {
|
|
newConfig := &ArtifactConfig{}
|
|
|
|
t, err := time.ParseDuration(*c.HTTPReadTimeout)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error parsing HTTPReadTimeout: %w", err)
|
|
}
|
|
newConfig.HTTPReadTimeout = t
|
|
|
|
s, err := humanize.ParseBytes(*c.HTTPMaxSize)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error parsing HTTPMaxSize: %w", err)
|
|
}
|
|
newConfig.HTTPMaxBytes = int64(s)
|
|
|
|
t, err = time.ParseDuration(*c.GCSTimeout)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error parsing GCSTimeout: %w", err)
|
|
}
|
|
newConfig.GCSTimeout = t
|
|
|
|
t, err = time.ParseDuration(*c.GitTimeout)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error parsing GitTimeout: %w", err)
|
|
}
|
|
newConfig.GitTimeout = t
|
|
|
|
t, err = time.ParseDuration(*c.HgTimeout)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error parsing HgTimeout: %w", err)
|
|
}
|
|
newConfig.HgTimeout = t
|
|
|
|
t, err = time.ParseDuration(*c.S3Timeout)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error parsing S3Timeout: %w", err)
|
|
}
|
|
newConfig.S3Timeout = t
|
|
|
|
return newConfig, nil
|
|
}
|
|
|
|
func (a *ArtifactConfig) Copy() *ArtifactConfig {
|
|
if a == nil {
|
|
return nil
|
|
}
|
|
|
|
newCopy := *a
|
|
return &newCopy
|
|
}
|