pomerium/internal/autocert/storage.go
Caleb Doxsey 6c3ed201da
autocert: add support for storage in s3 (#3793)
* autocert: add support for storage in s3

* go mod tidy

* skip on mac
2022-12-08 09:42:20 -07:00

79 lines
2.1 KiB
Go

package autocert
import (
"context"
"errors"
"fmt"
"regexp"
"strings"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/caddyserver/certmagic"
)
var (
errUnknownStorageProvider = errors.New("unknown storage provider")
s3virtualRE = regexp.MustCompile(`^([-a-zA-Z0-9]+)\.s3\.([-a-zA-Z0-9]+)\.amazonaws\.com(/.*)?$`)
s3hostRE = regexp.MustCompile(`^([^/]+)/([^/]+)(/.*)?$`)
)
// GetCertMagicStorage gets the certmagic storage provider based on the destination.
func GetCertMagicStorage(ctx context.Context, dst string) (certmagic.Storage, error) {
idx := strings.Index(dst, "://")
if idx == -1 {
return &certmagic.FileStorage{Path: dst}, nil
}
scheme := dst[:idx]
switch scheme {
case "s3":
bucket := ""
prefix := ""
var options []func(*config.LoadOptions) error
if match := s3virtualRE.FindStringSubmatch(dst[idx+3:]); len(match) == 4 {
// s3://{bucket}.s3.{region}.amazonaws.com/{prefix}
bucket = match[1]
prefix = match[3]
options = append(options, config.WithRegion(match[2]))
} else if match := s3hostRE.FindStringSubmatch(dst[idx+3:]); len(match) == 4 {
// s3://{host}/{bucket-name}/{prefix}
host := match[1]
bucket = match[2]
if strings.HasPrefix(match[3], "/") {
prefix = match[3][1:]
}
options = append(options,
config.WithRegion("us-east-1"),
config.WithEndpointResolver(aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) {
return aws.Endpoint{
PartitionID: "aws",
URL: "http://" + host,
SigningRegion: "us-east-1",
HostnameImmutable: true,
}, nil
})))
}
if prefix != "" && !strings.HasSuffix(prefix, "/") {
prefix += "/"
}
cfg, err := config.LoadDefaultConfig(ctx, options...)
if err != nil {
return nil, fmt.Errorf("autocert: error creating aws config: %w", err)
}
client := s3.NewFromConfig(cfg)
return &s3Storage{
client: client,
bucket: bucket,
prefix: prefix,
}, nil
}
return nil, errUnknownStorageProvider
}