Documentation
¶
Overview ¶
Package cdn signs download URLs on a CDN in front of an object store (decision 0029). A blob store that has a CDN takes one of these signers in its Options and answers blob.ViaCDN with the signer's URL for the blob's object key, so the store is never wrapped and keeps its other interfaces.
Every signer issues URLs on time windows: a URL minted in a window expires when the window ends plus the TTL, so a URL lives at least the TTL and at most twice it, and every client in one window is handed the same URL for a blob when the signature is deterministic.
Index ¶
- Constants
- Variables
- func Expiry(now time.Time, ttl time.Duration) (time.Time, error)
- func ParseCloudCDNKey(file []byte) ([]byte, error)
- func ParseDomain(domain string) (*url.URL, error)
- func ParsePrivateKey(pemBytes []byte) (crypto.Signer, error)
- func SignCloudCDN(rawURL, keyName string, key []byte, expires time.Time) string
- func Window(now time.Time, ttl time.Duration) (start, expiry time.Time, err error)
- type CloudCDN
- type CloudCDNConfig
- type CloudFront
- type CloudFrontConfig
- type FrontDoor
- type FrontDoorConfig
- type Request
- type Signer
Constants ¶
const ( HashSHA1 = "sha1" HashSHA256 = "sha256" )
CloudFront hash algorithms for CloudFrontConfig.Hash.
const CloudCDNKeySize = 16
CloudCDNKeySize is the length of a Cloud CDN signing key: 128 bits.
const CloudFrontMaxSize int64 = 50_000_000_000
CloudFrontMaxSize is the largest GET response CloudFront caches: AWS lists "Maximum cacheable file size per HTTP GET response" as 50 GB. Artifactory answered a larger file requested through CloudFront with 400 until 7.104.5 (RTDEV-49674), so a redirect sends such a file to the object store instead. The decimal reading of 50 GB is the smaller one, so no file over the limit is sent to the edge whichever unit AWS means.
Variables ¶
var ErrConfig = errors.New("cdn: invalid configuration")
ErrConfig reports an unusable CDN configuration.
Functions ¶
func Expiry ¶
Expiry is when a URL issued at now with ttl expires: the end of the current window plus ttl, where windows are ttl long and start on a multiple of ttl since the Unix epoch. Whole seconds, because every CDN expresses expiry in epoch seconds.
func ParseCloudCDNKey ¶
ParseCloudCDNKey decodes a Cloud CDN key file: base64url, with or without padding, around 16 raw bytes.
func ParseDomain ¶
ParseDomain reads a CDN domain: a host such as "d111.cloudfront.net", which means https, or an http or https URL with no path, such as "http://localhost:8080" for a test edge.
func ParsePrivateKey ¶
ParsePrivateKey reads a PEM RSA or ECDSA private key in any of the forms AWS and OpenSSL write: PKCS#1, SEC 1 or PKCS#8.
func SignCloudCDN ¶
SignCloudCDN signs rawURL as Google's documented algorithm does: append Expires and KeyName, take the HMAC-SHA1 of the whole URL with the raw key, and append it as a padded base64url Signature. Any query the URL already has, such as the response overrides, is part of what is signed.
func Window ¶
Window returns the window now falls in for ttl and the expiry of a URL issued in it, as Expiry does: windows are ttl long, start on a multiple of ttl since the Unix epoch, and a URL issued in one expires at its end plus ttl. A signer that fixes its start time to the window start, as an Azure SAS does, then issues the same URL for a blob throughout the window.
Types ¶
type CloudCDN ¶
type CloudCDN struct {
// contains filtered or unexported fields
}
CloudCDN signs URLs for a Cloud CDN backend bucket. It signs each URL whole rather than a URLPrefix: a prefix signature would open every blob under the prefix to whoever holds one URL.
Cloud CDN does not refuse unsigned requests; the bucket must be private, readable only by the cloud-cdn-fill service account, so that the origin refuses them (decision 0029).
func NewCloudCDN ¶
func NewCloudCDN(c CloudCDNConfig) (*CloudCDN, error)
NewCloudCDN returns a Cloud CDN signer.
type CloudCDNConfig ¶
type CloudCDNConfig struct {
// Domain is the load balancer host (see ParseDomain).
Domain string
// KeyName names the key on the backend bucket.
KeyName string
// Key is the key file's contents: 128 random bits, base64url, as
// "gcloud compute backend-buckets add-signed-url-key" reads them.
Key []byte
// PathPrefix is the path inside the bucket that the load balancer maps
// to its root; empty when it serves the bucket root.
PathPrefix string
// Now is the clock; nil means time.Now.
Now func() time.Time
}
CloudCDNConfig configures a Cloud CDN signer.
type CloudFront ¶
type CloudFront struct {
// contains filtered or unexported fields
}
CloudFront signs canned-policy URLs for a CloudFront distribution. The distribution's cache policy must key on the path plus response-content-disposition and response-content-type only: never the signature parameters, or every URL would be a cache miss, and always the overrides, or one item would be served with another's filename.
func NewCloudFront ¶
func NewCloudFront(c CloudFrontConfig) (*CloudFront, error)
NewCloudFront returns a CloudFront signer.
func (*CloudFront) Covers ¶
func (c *CloudFront) Covers(storePrefix string) error
Covers checks the distribution's origin reaches every key under storePrefix.
type CloudFrontConfig ¶
type CloudFrontConfig struct {
// Domain is the distribution host (see ParseDomain).
Domain string
// KeyPairID is the ID of the public key, in one of the distribution's
// trusted key groups, that matches PrivateKey.
KeyPairID string
// PrivateKey is the PEM private key: RSA as PKCS#1 or PKCS#8, or ECDSA
// as SEC 1 or PKCS#8.
PrivateKey []byte
// Hash is HashSHA1 (the default) or HashSHA256.
Hash string
// PathPrefix is the distribution origin's path inside the bucket; empty
// when the origin is the bucket root.
PathPrefix string
// Now is the clock; nil means time.Now.
Now func() time.Time
}
CloudFrontConfig configures a CloudFront signer.
type FrontDoor ¶
type FrontDoor struct {
// contains filtered or unexported fields
}
FrontDoor places read SAS URLs on an Azure Front Door endpoint (decision 0029). Front Door checks no signature of its own: it forwards the request, query string included, to the storage origin, which checks the SAS. So FrontDoor signs nothing and is not a Signer: the azure store mints a window-aligned SAS with its own credentials, which may need a network call for a user delegation key, and FrontDoor moves it onto the endpoint.
The route must key its cache on the full query string (query_string_caching_behavior = UseQueryString), or a cached private blob is served to anyone who asks for its path, and must cap cache expiry at the SAS window, because Front Door keeps serving a cached object after its SAS has expired.
func NewFrontDoor ¶
func NewFrontDoor(c FrontDoorConfig) (*FrontDoor, error)
NewFrontDoor returns a FrontDoor.
func (*FrontDoor) Covers ¶
Covers checks the endpoint reaches every blob under storagePrefix, the store's "<container>/<prefix>".
type FrontDoorConfig ¶
type FrontDoorConfig struct {
// Endpoint is the Front Door endpoint host, such as
// "artifacts-abc123.z01.azurefd.net" (see ParseDomain).
Endpoint string
// PathPrefix is the route's origin path: the leading part of
// "<container>/<blob name>" that the endpoint leaves out, for example the
// container when the origin path is "/<container>". Empty when the
// endpoint path is the whole storage path.
PathPrefix string
}
FrontDoorConfig configures a FrontDoor.
type Request ¶
type Request struct {
// TTL is the least time the URL stays valid once handed out.
TTL time.Duration
// Filename and ContentType, when set, travel as response overrides the
// CDN passes to the origin and keys its cache on.
Filename string
ContentType string
}
Request describes one signed URL.
type Signer ¶
type Signer interface {
// Provider names the CDN for logs and errors, for example "cloudfront".
Provider() string
// Covers returns an error unless every object key under storePrefix
// has a path on the CDN: a CDN whose origin is a folder of the bucket
// reaches only the keys inside it.
Covers(storePrefix string) error
// Sign returns a URL for objectKey, the key under the bucket's root.
Sign(objectKey string, r Request) (string, error)
}
Signer signs URLs for objects behind one CDN distribution.