Default a scheme-less s3.* endpoint to TLS (closes #158)
With the s3.* config form and an endpoint written without a scheme, use_ssl being omitted built an http:// endpoint, while config.example.yml documented use_ssl as defaulting to true. Over plain HTTP a network observer sees manifests, object names, sizes and the access key id, and can alter responses. use_ssl is now *bool: omitted (nil) means the default, TLS; only an explicit use_ssl: false forces plain HTTP. This matches the s3:// URL form, which already defaults to TLS. The config init template dropped its misleading use_ssl line from the s3:// block (that key is never read for URLs; ?ssl=false controls TLS there) and points at ?ssl=false instead. Model: opus-4-8
This commit was merged in pull request #178.
This commit is contained in:
@@ -192,8 +192,8 @@ storage_url: ""
|
|||||||
# access_key_id: YOUR_ACCESS_KEY
|
# access_key_id: YOUR_ACCESS_KEY
|
||||||
# secret_access_key: YOUR_SECRET_KEY
|
# secret_access_key: YOUR_SECRET_KEY
|
||||||
# # region: us-east-1 # Default: us-east-1
|
# # region: us-east-1 # Default: us-east-1
|
||||||
# # use_ssl: true # Default: true
|
|
||||||
# # part_size: 5MB # Multipart upload part size. Default: 5MB
|
# # part_size: 5MB # Multipart upload part size. Default: 5MB
|
||||||
|
# # For the s3:// form, disable TLS with ?ssl=false in the URL, not use_ssl.
|
||||||
|
|
||||||
# ─── OPTIONAL ────────────────────────────────────────────────────────────────
|
# ─── OPTIONAL ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,9 @@ type S3Config struct {
|
|||||||
AccessKeyID string `yaml:"access_key_id"`
|
AccessKeyID string `yaml:"access_key_id"`
|
||||||
SecretAccessKey string `yaml:"secret_access_key"`
|
SecretAccessKey string `yaml:"secret_access_key"`
|
||||||
Region string `yaml:"region"`
|
Region string `yaml:"region"`
|
||||||
UseSSL bool `yaml:"use_ssl"`
|
// UseSSL selects HTTPS for a scheme-less endpoint. Omitted (nil) means
|
||||||
|
// the default, TLS; set it to false only to force plain HTTP.
|
||||||
|
UseSSL *bool `yaml:"use_ssl"`
|
||||||
PartSize Size `yaml:"part_size"`
|
PartSize Size `yaml:"part_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,10 +111,11 @@ func storerFromParsedS3URL(parsed *URL, cfg *config.Config) (Storer, error) {
|
|||||||
func storerFromLegacyS3Config(cfg *config.Config) (Storer, error) {
|
func storerFromLegacyS3Config(cfg *config.Config) (Storer, error) {
|
||||||
endpoint := cfg.S3.Endpoint
|
endpoint := cfg.S3.Endpoint
|
||||||
|
|
||||||
// Ensure protocol is present
|
// Ensure protocol is present. Absent an explicit use_ssl, default to TLS;
|
||||||
|
// plain HTTP only when use_ssl is written as false.
|
||||||
if !strings.HasPrefix(endpoint, "http://") &&
|
if !strings.HasPrefix(endpoint, "http://") &&
|
||||||
!strings.HasPrefix(endpoint, "https://") {
|
!strings.HasPrefix(endpoint, "https://") {
|
||||||
if cfg.S3.UseSSL {
|
if cfg.S3.UseSSL == nil || *cfg.S3.UseSSL {
|
||||||
endpoint = "https://" + endpoint
|
endpoint = "https://" + endpoint
|
||||||
} else {
|
} else {
|
||||||
endpoint = "http://" + endpoint
|
endpoint = "http://" + endpoint
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package storage_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
|
"sneak.berlin/go/vaultik/internal/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
// legacyS3Config returns a minimal s3.* (no storage_url) configuration with a
|
||||||
|
// scheme-less endpoint. useSSL mirrors the config file: nil means the key is
|
||||||
|
// omitted, a pointer means it was written explicitly.
|
||||||
|
func legacyS3Config(useSSL *bool) *config.Config {
|
||||||
|
return &config.Config{
|
||||||
|
S3: config.S3Config{
|
||||||
|
Endpoint: "s3.example.com",
|
||||||
|
Bucket: "bucket",
|
||||||
|
AccessKeyID: "key",
|
||||||
|
SecretAccessKey: "secret",
|
||||||
|
Region: "us-east-1",
|
||||||
|
UseSSL: useSSL,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// endpointScheme builds the storer from cfg and returns the scheme its
|
||||||
|
// resolved endpoint carries (Info().Location is "endpoint/bucket").
|
||||||
|
func endpointScheme(t *testing.T, cfg *config.Config) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
storer, err := storage.NewStorer(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewStorer: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
location := storer.Info().Location
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(location, "https://"):
|
||||||
|
return "https"
|
||||||
|
case strings.HasPrefix(location, "http://"):
|
||||||
|
return "http"
|
||||||
|
default:
|
||||||
|
t.Fatalf("endpoint has no http(s) scheme: %q", location)
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLegacyS3SchemelessEndpointDefaultsToTLS(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
if got := endpointScheme(t, legacyS3Config(nil)); got != "https" {
|
||||||
|
t.Errorf("use_ssl omitted: got %q scheme, want https", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
no := false
|
||||||
|
if got := endpointScheme(t, legacyS3Config(&no)); got != "http" {
|
||||||
|
t.Errorf("use_ssl: false: got %q scheme, want http", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user